C++核心技术:智能指针
10 分钟阅读
•
1026 字
+
451 词
shared_ptr里有两个指针,其中一个指向控制块,一个指向真正的对象
shared_ptr的复制:复制两个指针,然后在控制块的引用计数+1
假设我们使用容器v来存储智能指针,那对于unique_ptr,每次执行push_back操作时必须使用一个右值,如下面:
v.push_back(createShape()); //createShape通过make_unique返回智能指针
v.push_back(std::move(uptr));//移动之后我们就不应该再使用uptr了
如果可以找到一个对象来明确负责另外一个对象的生存期,那么unique_ptr就足够了;只有在做不到这点时,才考虑使用shared_ptr。
使用shared_ptr的场景:
还是这句话,
在无关生存期的函数接口中不要使用智能指针
:
使用普通的引用(保证对象存在)或指针(对象不存在,指针为空)就好
反过来,如果一个函数确实就是要管理对象的所有权,那传参/返回值就该用智能指针,如下:
unique_ptr的删除器是模板的第二个参数,但是shared_ptr则没有将删除器当作模板参数。
这个区别的原因是:
unique_ptr追求的是低开销,和裸指针开销相似。而shared_ptr本来就需要为控制块额外分配内存,再增加删除操作的信息也不是什么问题。
对于shared_ptr来说,尽可能使用make_shared来创造智能指针,因为可以一次性分配控制器和对象的内存。
当我们继承了enable_shared_from_this的时候,可以利用shared_from_this()来从this指针获得一个shared_ptr。这样的类内部有一个指向自己的weak_ptr,但这个weak_ptr需要外部创建shared_ptr的时候来进行初始化,因此我们在构造函数内部不能立即开始执行利用到shared_from_this()的函数,否则shared_from_this会失败。
- 消息有多个并发处理者
- 异步代码需要把当前对象的进一步处理注册到某个异步回调上
- 写时复制的对象,允许同时读和修改的树形结构
智能指针的传递方式
unique_ptr<Obj> factory();//生产Obj
void sink(unique_ptr<Obj>);//消费Obj,转移所有权
void reseat(unique_ptr<Obj>&);//可能修改指针
void thinko(const unique_ptr<Obj>&);//这种情况就不需要使用智能指针了,因为不涉及到管理对象的所有权,这样使用智能指针没什么意义,完全可以用对象引用或者指针代替
shared_ptr<Obj> factory();//确知生产结果需要共享
void share(shared_ptr<Obj>);//将保留引用计数
void reseat(shared_ptr<Obj>&);//可能修改指针
void may_share(const shared_ptr<Obj>&);//可能保留引用计数
出于性能考虑,在最终保存智能指针时,我们都应该用右值形式如:
_saved = std::move(ptr);
删除器的行为定制
c++核心指南里和裸指针相关的条款
- 1.11:永远不要用原始指针(T*)或引用(T&)来转移所有权
- F.7:对于一般用途,使用原始指针(T*)或引用(T&)作为参数,而不是智能指针。
- C.12:不要把可拷贝或可移动类型的数据成员变成const或引用。
- R.3:原始指针(T*)不代表所有权