c++11 关于auto_ptr
- 智能指针需要引用头文件 <memory>
- c++ 11不再建议使用auto_ptr,编译时会产生 deprecated(及不赞成) 告警
- auto_ptr的功能可以被unique_ptr完全替换
auto_ptr代码示例
#include <iostream>
#include <memory>
using namespace std;
int main()
{
auto_ptr<string> p1 (new string("point to p1"));
auto_ptr<string> p2 = p1; // 此处赋值不会报错,但是会导致p1悬空
//后续对于p1的引用会崩溃
cout << "p2: " << *p2 << " ; p1: " << *p1 << endl;
}
unique_ptr代码示例
#include <iostream>
#include <memory>
using namespace std;
int main()
{
unique_ptr<string> p1(new string("point to p1"));
//unique_ptr<string> p2 = p1; // 赋值函数被声明为删除,
// 不允许外部引用赋值,编译时会报错
// 用编译期检查的手段 规避了悬空指针再次引用导致的崩溃问题
unique_ptr<string> p2 = move(p1); // 但是允许入参为 右值引用 的赋值函数
// 在用户明确知晓该特性,但仍执意赋值的情况下,仍可以使用右值引用的方式进行赋值
unique_ptr<string>&& p3 = move(p1);
//p2 = p3; //但是对于右值引用变量,编译时被作为左值处理,
//所以这种赋值方式仍会编译异常
// 下文使用完美转发语义,可以解决右值引用被作为左值变量处理的问题
unique_ptr<string> p4 = forward<unique_ptr<string>&&>(p3);
// 由于p1已经被右值引用赋值给p2,后文的p3和p4本质上都是对于p1的再次引用,
// 都会是悬空指针,如果尝试输出,会产生崩溃,
// 但是上述写法不影响对于定义的解释,可以用其他变量代替p1,来规避崩溃的问题
cout << "p2: " << *p2 << " ; p1: " << endl;
}
为了适配多次引用的情况,智能指针中增加引用计数,引入了shared_ptr类,可以采用make_shared<T>函数,或new运算符实现初始化;建议采用前者
但是还存在一个问题,就是循环引用会导致无法实现自动释放的功能。
#include <iostream>
#include <memory>
using namespace std;
class A {
public:
A() { cout << "A cons" << endl; }
~A() { cout << "A des" << endl; }
shared_ptr<A> _ptr; // 循环引用指针变量
shared_ptr<A> _ptr2;
shared_ptr<A> _ptr3;
shared_ptr<A> _ptr4;
};
int main()
{
A *pa = new A;
shared_ptr<A> ptr_a(pa);
shared_ptr<A> ptr_b(pa); // 使用new出来的指针初始化,具有重复初始化的风险,
// 会造成重复释放pa地址的崩溃问题
auto ptr1 = make_shared<A>();
cout << ptr1.use_count() << " " << ptr1.get() << endl;
ptr1->_ptr = ptr1; // 空指针赋值会造成引用计数增加
ptr1->_ptr = ptr1;
ptr1->_ptr = ptr1; // 非空指针的重复赋值不会造成计数重复增加,此处会输出2
cout << ptr1.use_count() << " " << ptr1.get() << endl;
ptr1->_ptr2 = ptr1;
ptr1->_ptr3 = ptr1;
ptr1->_ptr4 = ptr1; // 多个空指针的赋值会导致引用计数不断增加,此处在2基础上又加3,会输出5
cout << ptr1.use_count() << " " << ptr1.get() << endl;
// 程序结束时,仅有ptr1被析构,引用计数减1,为4,不为0,所以ptr1指向的A对象的实例不会被释放
// 因为实例不被释放,所以成员变量_ptrx都不会被析构,
// 继而引用计数永远不会减小,实例永远不会被自动释放的问题
return 0;
}
针对该问题,引入了weak_ptr,该类型的变量可以接收shared_ptr类型的指针,且赋值时不会导致其引用计数增加
#include <iostream>
#include <memory>
using namespace std;
class A {
public:
A() { cout << "A cons" << endl; }
~A() { cout << "~A desc" << endl; }
weak_ptr<A> _ptr;
};
int main()
{
auto ptr1 = make_shared<A>();
cout << ptr1.use_count() << " " << ptr1.get() << endl;
ptr1->_ptr = ptr1;
cout << ptr1.use_count() << " " << ptr1.get() << endl;
return 0;
}