mirror of
https://github.com/CnTransGroup/EffectiveModernCppChinese.git
synced 2024-12-28 05:40:43 +08:00
item19:update
This commit is contained in:
parent
e7ea0c9d1d
commit
587e885653
@ -1,4 +1,13 @@
|
||||
## Item 19:对于共享资源使用std::shared_ptr
|
||||
条款十九:对于共享资源使用std::shared_ptr
|
||||
|
||||
程序员使用带垃圾回收的语言指着C++笑看他们如何防止资源泄露。“真是原始啊!”它们嘲笑着说。“你们没有从1960年Lisp那里得到启发吗,机器应该自己管理资源生命周期而不应该依赖人类。”
|
||||
程序员使用带垃圾回收的语言指着C++笑看他们如何防止资源泄露。“真是原始啊!”它们嘲笑着说。“你们没有从1960年Lisp那里得到启发吗,机器应该自己管理资源生命周期而不应该依赖人类。”C++程序眼滚动眼珠。“你得到的启发就是只有内存算资源,其他资源释放都是非确定性的?我们更喜欢通用,可预料的销毁,谢谢你。”但我们的虚张声势可能底气不足。因为垃圾回收真的很方便,而且手动管理生命周期真的就像是使用石头小刀和兽皮制作可记忆内存电路。为什么我们不能同时有两个完美的世界:一个自动工作的世界(垃圾回收),一个销毁可预测的世界(析构)?
|
||||
|
||||
C++11中的`std::shared_ptr`将两者组合了起来。一个通过`std::shared_ptr`访问的对象其生命周期由指向它的指针们共享所有权(shbared ownership)。没有特定的`std::shared_ptr`拥有该对象。相反,所有指向它的`std::shared_ptr`都能相互合作确保它不再使用的那个点进行析构。当最后一个`std::shared_ptr`到达那个点,`std::shared_ptr`会销毁它所指向的对象。就垃圾回收来说,客户端不需要关心指向对象的生命周期,而对象的析构是确定性的。
|
||||
|
||||
`std::shared_ptr`通过引用计数来确保它是否是最后一个指向某种资源的制作,引用计数即资源和一个值关联起来,这个值会跟踪有多少`std::shared_ptr`指向该资源。`std::shared_ptr`构造函数递增引用计数值(通常——产检下面),析构函数递减值,拷贝复制运算符可能递增也可能递减。(如果sp1和sp2是`std::shared_ptr`并且指向不同对象,赋值运算符`sp1=sp2`会使sp1指向sp2指向的对象。直接效果就是sp1引用计数减一,sp2引用计数加一。)如果`std::shared_ptr`发现引用计数值为零,没有其他`std::shared_ptr`指向该资源,它就会销毁资源。
|
||||
|
||||
引用计数暗示着性能问题:
|
||||
+ **std::shared_ptr大小是原始指针的两倍**,因为它内部包含一个指向资源的原始指针,还包含一个资源的引用技术值
|
||||
+ **引用计数值必须动态分配**。 理论上,引用计数与所指对象关联起来,但是被指向的对象不知道这件事情。因此它们没有办法存放一个引用计数值。Item21会解释使用`std::make_shared`创建`std::shared_ptr`可以避免引用计数值的动态分配,但是还有一些`std::make_shared`不能使用的场景,这时候引用计数就会动态分配。
|
||||
+ **递增递减引用计数必须是原子性的**,因为多个reader、writer可能在不同的线程。
|
Loading…
Reference in New Issue
Block a user