我对在boost库中实现的智能指针有一些疑问。 shared_ptr和scoped_ptr之间唯一的区别是scoped_ptr没有复制构造函数而shared_ptr有吗? 当对象不调用复制构造函数时,我应该总是使用scoped_ptr而不是shared_ptr吗? 我也不明白共享/作用域数组的想法。我不能只使用std :: vector而不是它吗?
答案 0 :(得分:10)
是shared_ptr和scoped_ptr之间唯一的差异 scoped_ptr没有复制构造函数,shared_ptr有吗?
差异比这更重要;它与智能指针如何拥有它指向的对象有关。使智能指针与哑指针不同的是,所有权的概念是其功能的核心组成部分。所有权语义是区分不同类型智能指针的原因。
因为智能指针“拥有”他们所指向的东西,所以当智能指针消失时,他们可以做一些有用的事情,比如删除对象(仅使用语言规则就可以实现;不需要编译器魔法)。这样,内存管理几乎可以在C ++中自动完成(尽管声称相反,现代C ++中只需要很少的手动内存管理)。
shared_ptr
实现了reference-counting
semantics
内存管理。多个shared_ptr
可以拥有一个对象。一个
shared_ptr
离开并不一定会删除它的对象
指向,因为可能有另一个shared_ptr
拥有
宾语。拥有一个物体然后消失的最后一个shared_ptr
将会
删除它拥有的对象。
scoped_ptr
实现独占所有权语义。只有一个
scoped_ptr
可以拥有任何一个对象。当scoped_ptr
消失时,
它将始终删除它拥有的对象(因为只有一个
所有者)。它通常用作轻量级RAII机制
在免费商店分配的对象。
数组版本(shared_array
和scoped_array
)具有基本相同的语义,但专门针对数组设计,例如他们使用delete[]
而不是delete
,实现数组下标运算符等。
shared_ptr
和shared_array
还允许您指定自定义删除器,如果默认delete
行为不适合该对象。 scoped_ptr
和scoped_array
没有这种能力,因为与shared_ptr
和shared_array
相比,它们非常轻量级。
在C ++ 11中,最新和最新版本的C ++,还有一个unique_ptr
,就像scoped_ptr
一样,除了你可以将一个对象的所有权转移到另一个unique_ptr
}}。在C ++ 03中,一个较旧但更广泛支持的C ++版本,auto_ptr
等同于unique_ptr
,但它很容易以不安全的方式使用它(这就是它的原因)在C ++中弃用了11)。
我应该在对象时始终使用scoped_ptr而不是shared_ptr 不会调用复制构造函数吗?
您选择哪一个不依赖于复制构造函数的存在,因为shared_ptr
和scoped_ptr
不要求对象是可复制构造的。您可以根据所需的所有权语义选择一个。如果对象有多个所有者,则使用shared_ptr
。如果对象只有一个所有者且对象的存在仅在范围内,则使用scoped_ptr
(因此名称为scoped_ptr
)。
我也不了解共享/作用域数组的想法。我不能 使用std :: vector而不是它?
std::vector
没有像shared_array
那样实现引用计数语义。 std::vector
更像scoped_array
,但可以复制。复制std::vector
时,还会复制其包含的所有元素。 scoped_array
的情况并非如此。 std::vector
还具有允许您操纵和检查其内容的功能(例如push_back
,insert
,erase
等),但重量比{{1}重要得多}}
答案 1 :(得分:1)
是。 scoped_ptr
shared_ptr
不允许复制scoped_ptr
。但是这种“简单”的差异会对智能指针的实现和使用产生影响。
shared_ptr
比shared_ptr
更快更轻,因为不涉及引用计数。 XXX_ptr
将计算分配数量,而不是删除对象,直到所有引用都已过期/超出范围。
现在你关于向量的问题意味着你实际上并不熟悉动态分配的概念以及它与静态上的静态分配之间的区别。你真的应该研究一下C(++)的入门读物,并研究动态分配的原因以及何时需要它。
向量存储对象的列表。 {{1}}存储指向(单个)动态分配对象的指针。苹果和橘子。
答案 2 :(得分:1)
shared_ptr
与scoped_ptr
非常不同。 scoped_ptr
(现在在C ++ 11中标准化为std::unique_ptr
)只是一个RAII风格的智能指针,它获取资源的所有权,然后在指针超出范围时释放所拥有的资源。
但是,shared_ptr
可以与shared_ptr的其他实例共享资源的所有权。只要一个或多个shared_ptr
实例拥有它,资源就会保持活动状态。这是一种自动内存管理技术(一种垃圾收集形式),称为 reference counting 。它基本上提供与更高级的垃圾收集算法相同的效果,除了与其他垃圾收集技术不同,它不处理循环引用。
至于使用std::vector
与boost::scoped_array
,是的 - scoped_array
并没有真正提供太多优势。但是,boost::shared_array
提供了引用计数语义,就像shared_ptr
一样。
答案 3 :(得分:1)
如果你分配内存,你可以将新创建的指针放在一个范围指针中,这样如果malloc / noew失败,内存将被释放。这就是我通常使用它的方式,或者它是一个需要在堆上分配的对象,但是我想将它视为一个堆栈对象,它只会在范围结束之前一直存在。< / p>
共享指针是指如果要传递指针并允许对象拥有多个所有者。然后,没有一个所有者需要对该对象进行响应,他们都可以停止使用它并确保它将被释放出来。 (你不想释放你知道被其他人使用的对象)
答案 4 :(得分:1)
我会说你错误的想法。问题不在于你是否做调用复制构造函数 - 而是是否需要调用复制构造函数。换句话说,您应该决定是否使用shared_ptr或scoped_ptr,而不是基于读取代码,而是基于对对象所有权的思考以及对象的生命周期应该是什么。
假设你有一个想要在堆上创建的对象,而不是堆栈上的对象,无论出于什么原因(可能它太大而无法在堆栈上,也许你可能想在某个时候用不同的对象替换它) ,也许你希望它最近被初始化)但它的生命周期永远不应该超过它的包含范围。一个常见的例子是类中的实例变量:当它们所在的对象被删除时,它们应该经常被删除。然后,您应该使用scoped_ptr。
但有时您不知道何时可以安全删除某个对象。例如,考虑查找表中的对象。您想要返回它以响应查找,但是当它被删除时会发生什么 - 有人仍然可以使用之前查找过的对象吗?在这种情况下,您可以使用shared_ptr,它共享对象所有权,以便只有当没有人拥有指针副本时才会删除它。
那么为什么有人使用scoped_ptr而不是shared_ptr?首先,了解析构函数何时被调用是非内存管理语言(如C ++)的一大优势。也许析构函数很昂贵,或者它可能释放资源;很高兴知道这些事情何时发生。此外,使用shared_ptr时,如果意外创建循环引用,则可能会发生内存泄漏。
通常,几乎每个指针都应该“拥有” - 代码中应该有一个地方可以新闻和删除它。 scoped_ptr非常适合这个;当您希望将拥有的对象传递给非所有者时,您可以使用裸指针。但是如果您绝对需要共享对象的所有权,请使用shared_ptr - 只要您小心使用它!
对于作用域/共享数组,你当然可以使用std :: vector,但是数组更便宜,有时人们希望获得性能优势。