• C++ 提供了内存管理的绝对⾃由度
------->• 分配
------->• 释放
------->• 声明周期管理
•⼀些潜在严重问题
------->• 未初始化的指针(wild pointer),也就是野指针,可指向内存的任何位置
------->• 内存泄漏(memory leak),可能因为没有及时释放分配的内存空间
------->• 悬空指针(dangling pointer):指针指向已经释放的对象
• 所有权(ownership),引入智能指针
------->• 谁拥有指针?
------->• 何时可以删除指针?
• 也是对象
• 只能指向堆上分配的内存
• ⽤完后会⾃动删除
• 遵循RAII(资源获取即初始化)原则,对资源的申请释放,是一种成对操作的封装
• 几种C++ 智能指针:
------->• Unique pointers (unique_ptr)
------->• Shared pointers (shared_ptr)
------->• Weak pointers (weak_ptr)
------->• Auto pointers (auto_ptr) (已弃⽤)
- 导入 #include
- 在类模板(class templates)中定义
- 对原始指针做了封装
- 重载的操作符
- 解引⽤(*)
- 成员选择(->)
- 不⽀持算数操作符(++, — —等)
创建智能指针的具体实例如下,smart_pointer 可以换成上面提到的 unique_ptr,shared_ptr,weak_ptr,ptr 是指向 Type 类别的智能指针,当运行完 {} 里面的程序时,会自动调用析构函数,会帮助我们处理堆上分配的内存空间,
- unique_ptr
ptr_name
- 指向heap堆上类型 T 的对象
- 唯⼀(unique),多个 unique_ptr 不可以指向同⼀个对象
- 拥有指向对象的唯⼀所有权
- 不可以复制或赋值,但可以移动
- 指针使⽤完毕,被指向的对象会⾃动释放销毁
std::move(p1):转移p1拥有的所有权,容器 vec 拥有堆上面对象的所有权,p1 会设置为空指针,
make_unique 的作用也是在堆上创建的内存空间,
auto 关键字是编译器根据 make_unique 的返回值自动帮我们判断数据类型,
#include
#include
#include
#include
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 p1 {new Account {"jams", 1000.0}}; // 构造函数和析构函数都会被调用
// auto p2 = make_unique("mike", 2000.0); // 构造函数和析构函数都会被调用
// unique_ptr p3;
// // p3 = p2; // 报错,因为unique_ptr不允许拷贝,只能移动
// p3 = move(p2); // p2 会被置为null,即空指针
// if (! p2)
// cout << "p2 is null" << endl;
// auto p4 = make_unique("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;
}
- shared_ptr
ptr_name
- 指向heap堆上类型为 T 的对象
- 不唯⼀,多个shared_ptr可以指向同⼀个对象
- 被管理对象的所有权在多个shared_ptr中共享
- 可以复制或赋值
- 可以移动
- 引⽤计数(reference count)为0,被指向的对象会⾃动释放销毁
当超出 {} 的作用域后,堆上的对象也会自动销毁,
use_count():返回引用计数的值,也就是当前堆上的对象被多少 shared_ptr 管理,
p1.reset() 并没有释放 p1 所指向的对象,因为 p2 还在指向这个对象,
不再使用关键字 new,编译器也可以生成更高效的执行代码,
#include
#include
#include
#include
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 p1 {new int {100}};
// cout << "p1.use_count(): " << p1.use_count() << endl; // 1
// shared_ptr 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 p1 = make_shared("Alice", 1000.0);
// test_func(p1);
// cout << "p1.use_count(): " << p1.use_count() << endl; // 2
// {
// shared_ptr p2 = p1;
// cout << "p2.use_count(): " << p2.use_count() << endl; // 3
// {
// shared_ptr 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;
}