文章目录
- 1、智能指针简介
- 1.1 原始指针(raw pointer)的⼀些问题
- 1.2 智能指针(smart pointers)
- 2、智能指针(smart pointers)——unique_ptr
- 2.1 unique_ptr 的声明
- 2.2 unique_ptr 的函数
- 2.3 ⾃定义类型使⽤ unique_ptr
- 2.4 unique_ptr 不⽀持拷⻉、赋值
- 2.5 使⽤make_unique初始化(C++14标准)
- 代码:
- 3、智能指针(smart pointers)——shared_ptr
- 3.1 shared_ptr的声明
- 3.2 shared_ptr的函数
- 3.3 ⾃定义类型使⽤shared_ptr
- 3.4 vector和复制操作
- 3.5 使⽤make_shared初始化(C++11标注)
- 代码:
1、智能指针简介
1.1 原始指针(raw pointer)的⼀些问题
• C++ 提供了内存管理的绝对⾃由度
------->• 分配
------->• 释放
------->• 声明周期管理
•⼀些潜在严重问题
------->• 未初始化的指针(wild pointer),也就是野指针,可指向内存的任何位置
------->• 内存泄漏(memory leak),可能因为没有及时释放分配的内存空间
------->• 悬空指针(dangling pointer):指针指向已经释放的对象
• 所有权(ownership),引入智能指针
------->• 谁拥有指针?
------->• 何时可以删除指针?
1.2 智能指针(smart pointers)
• 也是对象
• 只能指向堆上分配的内存
• ⽤完后会⾃动删除
• 遵循RAII(资源获取即初始化)原则,对资源的申请释放,是一种成对操作的封装
• 几种C++ 智能指针:
------->• Unique pointers (unique_ptr)
------->• Shared pointers (shared_ptr)
------->• Weak pointers (weak_ptr)
------->• Auto pointers (auto_ptr) (已弃⽤)
- 导入 #include <memory>
- 在类模板(class templates)中定义
- 对原始指针做了封装
- 重载的操作符
- 解引⽤(*)
- 成员选择(->)
- 不⽀持算数操作符(++, — —等)
创建智能指针的具体实例如下,smart_pointer 可以换成上面提到的 unique_ptr,shared_ptr,weak_ptr,ptr 是指向 Type 类别的智能指针,当运行完 {} 里面的程序时,会自动调用析构函数,会帮助我们处理堆上分配的内存空间,
2、智能指针(smart pointers)——unique_ptr
- unique_ptr<T> ptr_name
- 指向heap堆上类型 T 的对象
- 唯⼀(unique),多个 unique_ptr 不可以指向同⼀个对象
- 拥有指向对象的唯⼀所有权
- 不可以复制或赋值,但可以移动
- 指针使⽤完毕,被指向的对象会⾃动释放销毁
2.1 unique_ptr 的声明
2.2 unique_ptr 的函数
2.3 ⾃定义类型使⽤ unique_ptr
2.4 unique_ptr 不⽀持拷⻉、赋值
std::move(p1):转移p1拥有的所有权,容器 vec 拥有堆上面对象的所有权,p1 会设置为空指针,
2.5 使⽤make_unique初始化(C++14标准)
make_unique 的作用也是在堆上创建的内存空间,
auto 关键字是编译器根据 make_unique 的返回值自动帮我们判断数据类型,
代码:
#include <iostream>
#include <vector>
#include <string>
#include <memory>
using namespace std;
class Account
{
private:
string name {"account"};
double balance {0.0};
public:
Account(string name = "none", double balance = 0.0);
~Account();
bool deposit(double amount);
void printInfo() const;
double getBalance();
};
Account::Account(string name, double balance)
:name {name}, balance {balance}
{
cout << "构造函数,name: " << name << endl;
}
Account::~Account()
{
cout << "析构函数,name: " << name << endl;
}
bool Account::deposit(double amount)
{
balance += amount;
return true;
}
void Account::printInfo() const
{
cout << "name: " << name << ", balance: " << balance << endl;
}
double Account::getBalance()
{
return balance;
}
int main()
{
// Account alice_account {"Alice", 1000.0}; // 构造函数和析构函数都会被调用
// Account * bob_account = new Account {"Bob", 2000.0}; // 只有构造函数被调用
// delete bob_account; // 析构函数被调用
// unique_ptr<Account> p1 {new Account {"jams", 1000.0}}; // 构造函数和析构函数都会被调用
// auto p2 = make_unique<Account>("mike", 2000.0); // 构造函数和析构函数都会被调用
// unique_ptr<Account> p3;
// // p3 = p2; // 报错,因为unique_ptr不允许拷贝,只能移动
// p3 = move(p2); // p2 会被置为null,即空指针
// if (! p2)
// cout << "p2 is null" << endl;
// auto p4 = make_unique<Account>("Helen", 3000.0);
// p4->deposit(1000.0);
// p4->printInfo(); // 调用成员函数
vector<unique_ptr<Account>> accounts;
accounts.push_back( make_unique<Account>("alice",1000));
accounts.push_back( make_unique<Account>("bob",500));
accounts.push_back( make_unique<Account>("mike",1000));
for (const auto &acc: accounts)
cout << acc->getBalance() << endl;
return 0;
}
3、智能指针(smart pointers)——shared_ptr
- shared_ptr<T> ptr_name
- 指向heap堆上类型为 T 的对象
- 不唯⼀,多个shared_ptr可以指向同⼀个对象
- 被管理对象的所有权在多个shared_ptr中共享
- 可以复制或赋值
- 可以移动
- 引⽤计数(reference count)为0,被指向的对象会⾃动释放销毁
3.1 shared_ptr的声明
当超出 {} 的作用域后,堆上的对象也会自动销毁,
3.2 shared_ptr的函数
use_count():返回引用计数的值,也就是当前堆上的对象被多少 shared_ptr 管理,
p1.reset() 并没有释放 p1 所指向的对象,因为 p2 还在指向这个对象,
3.3 ⾃定义类型使⽤shared_ptr
3.4 vector和复制操作
3.5 使⽤make_shared初始化(C++11标注)
不再使用关键字 new,编译器也可以生成更高效的执行代码,
代码:
#include <iostream>
#include <vector>
#include <string>
#include <memory>
using namespace std;
class Account
{
private:
string name {"account"};
double balance {0.0};
public:
Account(string name = "none", double balance = 0.0);
~Account();
void print() const;
};
Account::Account(string name, double balance)
:name {name}, balance {balance}
{
cout << "构造函数,name: " << name << endl;
}
Account::~Account()
{
cout << "析构函数,name: " << name << endl;
}
void Account::print() const
{
cout << "name: " << name << ", balance: " << balance << endl;
}
void test_func(shared_ptr<Account> p)
{
cout << "p.use_count(): " << p.use_count() << endl; // 2
}
int main()
{
// cout << "=====================" << endl;
// shared_ptr<int> p1 {new int {100}};
// cout << "p1.use_count(): " << p1.use_count() << endl; // 1
// shared_ptr<int> p2 {p1}; // 共享所有权
// cout << "p1.use_count(): " << p1.use_count() << endl; // 2
// p1.reset(); // 释放所有权,但是不会销毁对象,因为p2还在使用
// cout << "p1.use_count(): " << p1.use_count() << endl; // 0
// cout << "p2.use_count(): " << p2.use_count() << endl; // 1
// cout << "=====================" << endl;
// shared_ptr<Account> p1 = make_shared<Account>("Alice", 1000.0);
// test_func(p1);
// cout << "p1.use_count(): " << p1.use_count() << endl; // 2
// {
// shared_ptr<Account> p2 = p1;
// cout << "p2.use_count(): " << p2.use_count() << endl; // 3
// {
// shared_ptr<Account> p3 = p1;
// cout << "p3.use_count(): " << p3.use_count() << endl; // 4
// p1.reset();
// }
// cout << "p1.use_count(): " << p1.use_count() << endl; // 2
// cout << "p2.use_count(): " << p2.use_count() << endl; // 2
// }
// cout << "p1.use_count(): " << p1.use_count() << endl; // 1
cout << "=====================" << endl;
shared_ptr<Account> p1 = make_shared<Account>("Alice", 1000.0);
shared_ptr<Account> p2 = make_shared<Account>("Bob", 2000.0);
shared_ptr<Account> p3 = make_shared<Account>("Charlie", 3000.0);
vector<shared_ptr<Account>> accounts;
accounts.push_back(p1);
accounts.push_back(p2);
accounts.push_back(p3);
for (const auto &p: accounts)
{
p->print();
cout << "p.use_count(): " << p.use_count() << endl; // 1
}
return 0;
}