智能指针的基本哲学是 RAII(Resource Acquisition Is Initialization)。RAII 的理念是将资源的获取放在类的构造函数里,资源的释放放在类的析构函数里。在类的生存期结束的时候,析构函数会被自动调用,对应的资源将会释放。
1. shared_ptr
- shared_ptr内部使用引用计数,每一个shared_ptr的拷贝都指向相同的内存,引用计数减为0时,自动释放所指向的堆内存。
- 不要用一个原始指针初始化多个shared_ptr,否则会二次释放同一内存。
- shared_ptr会出现循环引用问题,使用weak_ptr可以解决。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
{
// 初始化(推荐)
shared_ptr<int> ptr1 = make_shared<int>(100);
// 拷贝构造函数
shared_ptr<int> ptr2(ptr1);
cout << ptr1.use_count() << endl; // 2
int* p = new int(200);
// 不能这样构造
//shared_ptr<int> ptr3 = p;
// 不能将普通指针直接赋值给一个智能指针
//ptr1 = p;
// 初始化
shared_ptr<int> ptr3(p);
// 赋值运算符
ptr2 = ptr3;
cout << ptr1.use_count() << endl; // 1
cout << ptr2.use_count() << endl; // 2
cout << ptr1.unique() << endl; // 1
// 获取原始指针
int* q = ptr3.get();
// 解引用运算符
cout << *ptr1 << endl; // 100
cout << *q << endl; // 200
swap(ptr1, ptr3);
cout << *ptr1 << endl; // 200
cout << *ptr3 << endl; // 100
}
system("pause");
return 0;
}
当智能指针中有值时,调用reset()会使引用计数减1。当调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将就对象的引用计数减1,如果发现引用计数为0时,则析构旧对象,然后将新对象的指针交给智能指针保管。
#include <iostream>
#include <memory>
using namespace std;
class Person
{
public:
Person(int id) :_id(id) {
cout << "Constructor, id = " << _id << endl;
}
~Person() {
cout << "Destructor, id = " << _id << endl;
}
public:
int _id;
};
int main()
{
{
shared_ptr<Person> p1 = make_shared<Person>(100);
p1.reset(new Person(200)); // Destructor, id = 100
shared_ptr<Person> p2(p1);
cout << p1.use_count() << endl; // 2
p1.reset();
cout << p2.use_count() << endl; // 1
}
system("pause");
return 0;
}
2. unique_ptr
- 通过禁止拷贝语义、只有移动语义,实现同一时刻只能有一个unique_ptr指向给定对象。
- unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,默认使用delete操作符,用户可以自定义删除器。
#include <iostream>
#include <memory>
using namespace std;
class Person
{
public:
Person(int id) :_id(id) {
cout << "Constructor, id = " << _id << endl;
}
~Person() {
cout << "Destructor, id = " << _id << endl;
}
public:
int _id;
};
int main()
{
Person* p = new Person(100);
// 不能这样构造
//unique_ptr<Person> ptr = p;
unique_ptr<Person> ptr1(p);
// ->运算符
cout << ptr1->_id << endl; // 100
ptr1.reset(); // Destructor, id = 100
//ptr = nullptr; // 这样也可以,Destructor, id = 100
unique_ptr<Person> ptr2(new Person(200));
// 不能将普通指针直接赋值给一个智能指针
//ptr = ptr2;
// 不能拷贝构造
//unique_ptr<Person> ptr3(ptr2);
{
// 转移所有权
unique_ptr<Person> ptr4 = move(ptr2);
cout << ptr4->_id << endl; // 200
} // Destructor, id = 200
unique_ptr<Person> ptr5(new Person(300));
// 释放所有权
Person* ptr = ptr5.release();
cout << ptr->_id << endl; // 300
// 注意delete!
delete ptr;
system("pause");
return 0;
}
3. weak_ptr
- 观察者功能:通过shared_ptr管理数据并将weak_ptr提供给用户,用户可以通过expired()或者lock()来检测数据的有效性。当你想使用对象,但是并不想管理对象,并且在需要使用对象时可以判断对象是否还存在时使用。
- 解决循环引用问题。
- weak_ptr辅助shared_ptr,只能指向shared_ptr对象。
- 赋值给它不会增加引用计数!
// shared_ptr的循环引用问题
#include <iostream>
#include <memory>
using namespace std;
class CB;
class CA
{
public:
CA() {
cout << "CA's Constructor" << endl;
}
~CA() {
cout << "CA's Destructor" << endl;
}
void set_ptr(shared_ptr<CB>& ptr) {
m_ptr_b = ptr;
}
void b_use_count() {
cout << "b use count : " << m_ptr_b.use_count() << endl;
}
private:
shared_ptr<CB> m_ptr_b;
};
class CB
{
public:
CB() {
cout << "CB's Constructor" << endl;
}
~CB() {
cout << "CB's Destructor" << endl;
}
void set_ptr(shared_ptr<CA>& ptr) {
m_ptr_a = ptr;
}
void a_use_count() {
cout << "a use count : " << m_ptr_a.use_count() << endl;
}
private:
shared_ptr<CA> m_ptr_a;
// 使用weak_ptr,解决循环引用问题
// weak_ptr<CA> m_ptr_a;
};
int main()
{
{
shared_ptr<CA> ptr_a(new CA);
shared_ptr<CB> ptr_b(new CB);
cout << "a use count : " << ptr_a.use_count() << endl; // 1 -> 1
cout << "b use count : " << ptr_b.use_count() << endl; // 1 -> 1
ptr_a->set_ptr(ptr_b);
ptr_b->set_ptr(ptr_a);
cout << "a use count : " << ptr_a.use_count() << endl; // 2 -> 1
cout << "b use count : " << ptr_b.use_count() << endl; // 2 -> 2
}
system("pause");
return 0;
}
-
使用shared_ptr可能出现循环引用的问题
-
使用weak_ptr解决循环引用问题
#include <iostream>
#include <memory>
using namespace std;
class Person
{
public:
Person(int id) :_id(id) {
cout << "Constructor, id = " << _id << endl;
}
~Person() {
cout << "Destructor, id = " << _id << endl;
}
void show() {
cout << "Person, id = " << _id << endl;
}
public:
int _id;
};
void test01()
{
// 不能定义指向原始指针的weak_ptr
//weak_ptr<Person> ptr_1(new Person(100));
shared_ptr<Person> ptr_1(new Person(100));
cout << ptr_1.use_count() << endl; // 1
shared_ptr<Person> ptr_2 = ptr_1;
cout << ptr_1.use_count() << endl; // 2
cout << ptr_2.use_count() << endl; // 2
// weak_ptr不增加引用计数
weak_ptr<Person> wk_ptr = ptr_1;
cout << ptr_1.use_count() << endl; // 2
cout << ptr_2.use_count() << endl; // 2
// 无法从“std::weak_ptr<Person>”转换为“std::shared_ptr<Person>”
// shared_ptr<Person> ptr_3 = wk_ptr;
}
void test02()
{
shared_ptr<Person> ptr1(new Person(100));
shared_ptr<Person> ptr2(ptr1);
cout << ptr1.use_count() << endl; // 2
weak_ptr<Person> wk_ptr = ptr1;
cout << wk_ptr.use_count() << endl; // 2
if (!wk_ptr.expired())
{
// 无->运算符
//wk_ptr->show();
// 获取weak_ptr对应的shared_ptr对象
wk_ptr.lock()->show();
}
// 将wk_ptr1的置空
wk_ptr.reset();
if (wk_ptr.expired())
{
cout << "wk_ptr is invalid" << endl; // 指针已经无效
}
// 赋值运算符
wk_ptr = ptr2;
if (!wk_ptr.expired())
{
wk_ptr.lock()->show(); // 赋值操作后,指针有效
}
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
参考:https://blog.youkuaiyun.com/albertsh/article/details/82286999
参考:https://blog.youkuaiyun.com/shaosunrise/article/details/85158249