刚刚开始研究智能指针以及它们如何用于提高代码内的效率,我很好奇shared_ptr如何对数组/向量/容器中的类对象作出反应。
从我所读到的,共享指针的一般要点是,一旦指向一个对象的所有指针都被销毁或重新分配,该对象也会被破坏。但是,如果我们的对象也存储在数组/向量中,那么共享指针仍然会尝试销毁该对象,即使它仍然可以访问。
是否有某种方法可以设置包含数组的共享指针,这样您就可以确保在清除数组/向量后只删除对象,或者是否必须在数组中使用shared_ptr ?
答案 0 :(得分:2)
不鼓励将裸参考与shared_ptr混合。主要原因是它打破了引用计数概念,这是shared_ptr用于确定何时可以安全地释放引用对象的概念。任何裸引用必须的寿命比最长寿命的shared_ptr短,否则崩溃正在酝酿中。
如果要在某种容器中包含一组对象,并且仍然能够使用shared_ptr访问这些对象,最好使用shared_ptr的数组/向量/容器,因为这会带来容器“进入折叠“可以说与shared_ptr概念。这样做的好处是,当从容器中删除对象时,它不会立即被释放,反之亦然,引用它的共享指针。
使用shared_ptrs容器的缺点是它使得指针数学稍微困难一些,因为实际上,你使用了一种指向指针的指针。
答案 1 :(得分:2)
您只能以两种方式使用共享指针:
1)创建新对象时,
std::shared_ptr<something> ptr(new something);
2)将共享指针复制到另一个时。
std::shared_ptr<something> copy(ptr);
因此,如果在数组中创建一个对象,它将不适合共享指针方案。
如果要在向量中保存使用共享指针分配的对象,则必须保存其共享指针:
std::vector<std::shared_ptr<something> > my_vector;
my_vector.push_back(new something);
清除向量时,所有指针都会被清除,因此只有向量引用的对象会被删除:
my_vector.clear(); // do "delete something" as required
作为旁注,你在问题中说“效率更高”......共享指针的效率并不高,并且它们不太可能在你的软件中创建比你想象的更多的代码。
C ++中一个非常重要的例外是异常。保存在智能指针中的对象(在这种情况下unique_ptr也可以工作)将在异常时自动删除。这是非常重要的。例如:
std::shared_ptr<something> ptr(new something);
...
if(this_is_true) throw std::logic_error("something's wrong");
...
在上面的代码中,指针ptr
会在throw返回之前自动删除。这不是我所说的更有效,但在清洁方面要好得多。如果你调用一个可以抛出的函数(例如另一个new
),那么处理每个调用变得非常繁琐(即你需要在每次调用时都有一个try / catch,并且catch必须删除指针,然后重新抛出。)
所以从这个意义上说,它是有效率的。但是,就执行速度而言,它可能没有比不使用共享指针更快(或更慢)。
答案 2 :(得分:1)
指向子对象(数组元素或对象成员)的指针可以与指向整个对象的指针共享所有权。使用模板构造函数创建shared_ptr
到子对象:
template< class Y >
shared_ptr( const shared_ptr<Y>& r, T *ptr );
它接受任何类型的shared_ptr
和指向目标类型的指针(可能完全不相关)。构造的shared_ptr
与源对象r
共享所有权,但当取消引用时指向ptr
。
例如,创建指向std::array
的第三个数组元素的指针:
class foo {};
auto array = std::make_shared<std::array<foo, 16>>();
auto element_ptr = std::shared_ptr<foo>(array, array->data() + 2);
或对象的数据成员:
struct foo {
int i;
};
auto some_foo = std::make_shared<foo>();
auto foo_member = std::shared_ptr<int>(some_foo, &some_foo->i);
遗憾的是,没有方便的类型推导“make”函数,例如std::make_shared
,显然指定子对象的类型很烦人。也许我们应该写自己的:
template <typename Object, typename SubObject>
inline std::shared_ptr<SubObject>
make_sub_ptr(const std::shared_ptr<Object>& c, SubObject* ptr) {
return {c, ptr};
}
所以我们可以将早期的创作简化为:
auto element_ptr = make_sub_ptr(array, array->data() + 2);
// ...
auto foo_member = make_sub_ptr(some_foo, &some_foo->i);
<强> Live Demo at Coliru 强>