请你说一下你理解的c++中的smart pointer四个智能指针:
shared_ptr,unique_ptr,weak_ptr,auto_ptr
说auto_ptr
和unique_ptr
不说移动语义?
C++11之前没有移动的说法,因此auto_ptr
只能凡复制就转移所有权。新引入了右值引用和移动语义之后,unique_ptr
禁止复制构造,只能移动构造,避免了auto_ptr
的问题。转移所有权只能自己写p2 = std::move(p1)
,写了个如此显眼的move
之后还要自己去访问p1
只能说手贱没治。
另外shared_ptr
允许shared_ptr<void>
来管理任何类型指针并且确保正确析构(但是unique_ptr
是不行的),这是因为shared_ptr
的管理块中存储了类型擦除后的Deleter
用来析构。在C++标准中它和unique_ptr
的声明是不一样的:
template class shared_ptr; template <class T, class Deleter = std::default_delete<T> > class unique_ptr; template class unique_ptr;
std::default_delete
就是纯粹包装了一下delete
/delete[]
。
shared_ptr
不带Deleter
模板参数而unique_ptr
带,与之对应shared_ptr
的构造函数中是可以自行提供Deleter
而unique_ptr
不行(而且shared_ptr
的构造函数是模板函数)。那么只要shared_ptr<void>
在构造的时候,根据传入的指针类型推断出正确的Deleter
保存下来,在析构的时候调用即可实现正确析构。
与之同理,在处理继承的情况时,shared_ptr<Base> p{ new Derived() }
也能正确调用Derived
的析构函数,即使析构函数不是virtual的。同样unique_ptr
不支持这种行为,非virtual析构函数情况下,不手动指定Deleter
(也即std::unique_ptr<Base, std::default_delete<Derived>> p{ new Derived() }
)的话它只会调用~Base
。
最后,因为shared_ptr
支持这些复杂功能,因此其中的管理块存储的不只是一个引用计数。所以在创建新的shared_ptr
的时候不要直接调用构造函数,传入的对象一次new,管理块一次new,两次内存申请。无特殊情况应该用std::make_shared<T>
,只会申请一次内存。unique_ptr
没有这个问题,用构造函数或者C++14为了形式上统一引进的std::make_unique<T>
都是可以的。