C++ shared_ptr和unique_ptr
TTOR 人气:0shared_ptr
基本用法: 可以通过构造函数, make_shared<T>辅助函数和reset()方法来初始化shared_ptr
1. 初始化方法
shared_ptr<int> p1(new int(1)); shared_ptr<int> p2 = p1; shared_ptr<int> p3; p3.reset(new int(1)); shared_ptr<int> p4 = make_shared<int>(int(5));
优先使用make_shared来构造, 更加高效
不能用一个原始指针直接赋值智能指针, 以下方式是错误的
shared_ptr<int> p5=new int(1); //error
2.获取智能指针的原始指针: 通过get方法
shared_ptr<int> ptr = make_shared<int>(int(5)); int *p=ptr.get();
3.指定删除器:自定义指针销毁方式
void ptr_deleter(const int*p) { delete p; } shared_ptr<int> p(new int, ptr_deleter);
第二个参数指定删除器(一个可调用对象, 其中参数为该类型的指针, 如上面为int*)
当shared_ptr引用计数为0时, 调用传入的而不是默认的删除器来释放对象的内存
当用shared_ptr管理动态数组时, 需要指定删除器, 因为shared_ptr默认删除器不支持数组对象
如下使用lambda表达式作为删除器
shared_ptr<int> p(new int[10],[](int*p){delete []p;});
通过default_delete作为删除器, 同时封装一个make_shared_array函数来支持数组
template<typename T> shared_ptr<T> make_shared_array(int size) { return shared_ptr<T>(new T[size],default_delete<T[]>()); }
(自测)貌似这样也支持数组
shared_ptr<int[]> ptr(new int[10]);
使用shared_ptr注意
(1)不要用一个原始指针初始化多个shared_ptr
int *ptr = new int; shared_ptr<int> p1(ptr); shared_ptr<int> p2(ptr); //错误
(2)不要在函数实参中创建shared_ptr
function(shared_ptr<int>(new int),g());
参数的计算顺序可能没有固定顺序, 若是new int后执行g()抛出异常, 则shared_ptr还没有创建, 则new int内存泄漏了
(3)不要用this指针构造shared_ptr作为返回值
class A { public: shared_ptr<A> get_self() { return shared_ptr<A>(this); } ~A() { cout << ("destructor") << endl; } }; int main() { shared_ptr<A> p1(new A); shared_ptr<A> p2 = p1->get_self(); return 0; }
destructor
destructor
以上代码p1和p2相当于同一个new A初始化, 会shared_ptr销毁时, 会重复析构
正确做法:
让该类继承enable_shared_from_this<>, 同时调用shared_from_this()返回
class A :public enable_shared_from_this<A> //继承 { public: shared_ptr<A> get_self() { return shared_from_this(); //调用该函数 } ~A() { cout << ("destructor") << endl; } }; int main() { shared_ptr<A> p1(new A); shared_ptr<A> p2 = p1->get_self(); return 0; }
destructor
只要用shared_ptr, 调用的成员函数里都不能使用this构造, 否则都会出错
class A { public: void test() { shared_ptr<A>(this); //错误 } ~A() { cout<<( "destructor" )<<endl; } }; shared_ptr<A> p(new A); p->test()
另外, 不要在构造函数里使用shared_from_this
(4)避免循环引用
以下代码会由于循环引用, 引用计数值都为1, 导致两个指针都不会析构
class A; class B; class A { public: shared_ptr<B> b_ptr; ~A() { cout << ("A destructor") << endl; } }; class B { public: shared_ptr<A> a_ptr; ~B() { cout << ("B destructor") << endl; } }; int main() { shared_ptr<A> a_p(new A); shared_ptr<B> b_p(new B); a_p->b_ptr=b_p; b_p->a_ptr=a_p; }
//没有输出
unique_ptr
unique_ptr不允许复制, 不允许其他的智能指针共享其内部的指针, 但可以转移
unique_ptr<int> ptr(new int); // unique_ptr<int> ptr2=ptr; error 不可以赋值 unique_ptr<int> ptr3=move(ptr); //用move进行转移 assert(ptr!=nullptr); //转移后ptr为nullptr
自定义make_unique函数且让其支持定长数组
思路
不是数组, 返回unique_ptr<T>
是数组且非定长数组, 返回unique_ptr<T>, 即不应该调用make_unique<T[10]>(10)而是make_unique<T[]>(10)
最后过滤掉该定长数组(函数声明为delete)
// !is_array_v确定不是数组, 返回unique_ptr<T> template<typename T,typename ...Args> enable_if_t<!is_array_v<T>,unique_ptr<T>> make_unique_(Args&&...args) { return unique_ptr<T>( new T(forward<Args>(args)...)); } //定长数组如T[10], 不应该调用make_unique<T[10]>(10);而是make_unique<T[]>(10); // is_array_v确定是数组且!extent_v<T>确定非定长数组, 返回unique_ptr<T> template<typename T,typename ...Args> enable_if_t<is_array_v<T>&&!extent_v<T>,unique_ptr<T>> make_unique_(size_t size) { using U=remove_extent_t<T>; return unique_ptr<T>( new U[size]); } //否之过滤掉该定长数组 template<typename T,typename ...Args> enable_if_t<extent_v<T>,void> make_unique_(Args&&...)=delete;
unique_ptr<int> ptr= make_unique_<int>(10); unique_ptr<int[]> ptr1= make_unique_<int[]>(10);
不过unique_ptr本身也支持数组, shared_ptr自测也支持, 如下
unique_ptr<A[]> ptr1(new A[10]); shared_ptr<A[]> ptr2(new A[10]);
unique_ptr也支持删除器, 但和shared_ptr有区别, 要指定删除器类型
shared_ptr<A> p1(new A[10],[](A*p){delete []p;}); // unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 错误 unique_ptr<A,void(*)(A*)> p2(new A[10],[](A*p){delete []p;}); //正确
如果希望lambda删除器捕获变量, 则需要用function包装
unique_ptr<A,void(*)(A*)> p1(new A[10],[&](A*p){delete []p;}); //错误 unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正确
加载全部内容