顺便在此记录学习C++智能指针的一些重点和遗忘点。
首先需包含头文件 <memory>,并且智能指针命名空间在std中。
C++智能指针主要有三种:(1)shared_ptr / (2)unique_ptr / (3)weak_ptr
shared_ptr 最常用,没有什么限制;
unique_ptr 指分配的对象被一个指针所独占;
weak_ptr 是一种不控制对象生命周期的一种指针(不修改对象的引用计数)。
必须要注意的是,指针本身是栈空间里的,但指向的内容如果是通过动态内存分配的,则指向的内容是在堆中的。例如:
// 这里sp本身在栈中,指向的这个“10”的int空间在堆中。
shared_ptr<int> sp = make_shared<int>(10);// make_shared是较安全的智能指针初始化方法
shared_ptr通过对象的引用计数来自动控制动态分配的资源销毁,故不需要手动调用delete,调试时可用use_count()函数获取当前对象引用计数的值,所谓引用计数,就是针对某对象,总共有多少指针指向它。
shared_ptr<int> sp = make_shared<int>(1);
cout << sp.use_count() << endl; // 此时打印1
shared_ptr<int> sp2 = sp; // 此时sp2和sp指向同个对象,因此该对象的引用计数变为2
cout << sp.use_count() << endl; // 此时打印2
shared_ptr两种初始化方法(直接初始化、make_shared):
// 直接调用new int()
shared_ptr<int> sp1(new int());
// 调用make_shared,隐式调用int的默认构造函数
shared_ptr<int> sp2 = make_shared<int>();
// 调用make_shared,隐式调用参数为1的int构造函数
shared_ptr<int> sp3 = make_shared<int>(1);
// 调用make_shared,调用参数为"hello"的string构造函数
shared_ptr<string> sp4 = make_shared<string>("hello");
unique_ptr也有两种初始化方法,和shared_ptr类似,不过make_unique方法是C++14中才有的:
unique_ptr<int> up(new int());
unique_ptr<int> up1(new int(1));
unique_ptr<int> up2 = make_unique<int>();
使用shared_ptr或unique_ptr方法和 裸指针 一样,直接解引用即可,使用weak_ptr则需要先调用lock()返回一个shared_ptr类型指针,然后再使用:
shared_ptr<int> sp(new int());
weak_ptr<int> wp = sp;
cout << *(wp.lock()) << endl; // wp.lock()返回shared_ptr类型
解释下weak_ptr为什么不控制对象的生命周期:当有个新的weak_ptr指向某对象时,并不会给该对象的引用计数加1,也就是说weak_ptr不会改变对象的引用计数,因此不会影响到对象的销毁。但是这样一来,就有种特殊情况:对象的引用计数已经是0了(代表已经释放),这时调用了weak_ptr读取或者操作该对象,程序会出现未定义的行为,此时应用以下代码:
weak_ptr<int> wp; // 声明一个weak_ptr
{
shared_ptr<int> sp = make_shared<int>(1);
wp = sp;
} // 退出该代码块时,shared_ptr指向的对象会释放,即wp指向的对象已释放了
// cout << *(wp.lock()) << endl; // 这里报错,因为此时对象已过期,程序出现未定义行为
// 应该用下面的代码读取,expired代表对象已过期
if (!wp.expired()) {
cout << *(wp.lock()) << endl;
}
weak_ptr常被用来避免循环引用导致的内存泄漏问题,循环引用的详细问题可参考:【C++】weak_ptr弱引用智能指针详解_Yngz_Miao的博客-CSDN博客