繁体   English   中英

C ++共享指针引用数组中的对象

[英]C++ shared pointers referencing an object within an array

才刚刚开始研究智能指针,以及如何使用它们来提高代码内的效率,我很好奇shared_ptr如何与数组/向量/容器中的类对象反应。

从我读过的共享指针的一般要点来看,一旦所有指向一个对象的指针都被破坏或重新分配,该对象也将被破坏。 但是,如果我们的对象也存储在数组/向量中,即使共享对象仍然可以访问,共享指针是否仍会尝试销毁该对象。

有没有什么办法可以在设置数组时设置共享指针,这样可以确保仅在清除数组/向量后才删除对象,还是必须在数组中使用shared_ptr?

不建议将裸引用与shared_ptr混合使用。 主要原因是因为它违反了引用计数的概念,shared_ptr用来确定何时可以安全地解除分配引用的对象。 任何裸引用的生存期必须比寿命最长的shared_ptr的生存期短,否则崩溃就会酝酿。

如果您想在某种容器中包含一组对象,并且仍然能够使用shared_ptr访问这些对象,则最好使用shared_ptr的数组/向量/容器,因为这会使容器“折叠” ”可以说是shared_ptr概念。 这样做的好处是,当从容器中删除对象时,将不会立即释放该对象,反之亦然,引用该对象的共享指针也是如此。

使用shared_ptrs容器的缺点是,由于实际上使用的是指向指针的指针,因此指针数学变得稍微困难​​些。

您应该仅以两种方式使用共享指针:

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在抛出ptr之前自动被删除。 这不是我所说的更有效,但是在清洁度方面要好得多。 如果您调用一个可以抛出的函数(例如,另一个new函数),则处理每个调用将变得非常乏味(即,您需要在每次调用中都进行一次try / catch,并且catch必须删除指针并然后重新抛出。)

因此从某种意义上讲,它是有效的。 但是,就执行速度而言,它可能比不使用共享指针快(或慢)。

指向子对象(数组元素或对象成员)的指针可能与指向整个对象的指针共享所有权。 使用模板构造函数为子对象创建shared_ptr

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

它接受任何类型的shared_ptr ,以及指向目标类型的指针(可能完全不相关)。 构造的shared_ptr与源对象r共享所有权,但是在取消引用时指向ptr

例如,创建一个指向std::array的第三个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);

可惜没有像std::make_shared这样方便的类型推断“ make”功能,明确指定子对象的类型很烦人。 也许我们应该自己写:

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);

Coliru现场演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM