简体   繁体   English

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

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

Only just started looking into smart pointers and how they can be used to improve efficiency within code and I'm curious as to how shared_ptr reacts with class objects within an array/vector/container. 才刚刚开始研究智能指针,以及如何使用它们来提高代码内的效率,我很好奇shared_ptr如何与数组/向量/容器中的类对象反应。

From what i've read the general gist of shared pointers is that once all of them pointing to an object have been destroyed or reallocated, the object is also destroyed. 从我读过的共享指针的一般要点来看,一旦所有指向一个对象的指针都被破坏或重新分配,该对象也将被破坏。 However if our object is also stored within an array/vector, does the shared pointer still attempt to destroy the object even though it is still accessible. 但是,如果我们的对象也存储在数组/向量中,即使共享对象仍然可以访问,共享指针是否仍会尝试销毁该对象。

Is there some way to set up shared pointers with arrays in mind so you can ensure that you only delete the objects once you go to clear your array/vector, or would you have to resort to using shared_ptr in your array as well? 有没有什么办法可以在设置数组时设置共享指针,这样可以确保仅在清除数组/向量后才删除对象,还是必须在数组中使用shared_ptr?

Mixing naked references with a shared_ptr is to be discouraged. 不建议将裸引用与shared_ptr混合使用。 The main reason is because it breaks the reference count concept, which is what the shared_ptr uses to determine when it is safe to deallocate the referenced object. 主要原因是因为它违反了引用计数的概念,shared_ptr用来确定何时可以安全地解除分配引用的对象。 Any naked references must have a shorter lifetime than the longest-living shared_ptr, otherwise a crash is brewing. 任何裸引用的生存期必须比寿命最长的shared_ptr的生存期短,否则崩溃就会酝酿。

If you want to contain a set of objects in a container of some sort, and still be able to access those objects using a shared_ptr, it's best to use an array/vector/container of shared_ptr's, as this brings the container "into the fold" so to speak with the shared_ptr concept. 如果您想在某种容器中包含一组对象,并且仍然能够使用shared_ptr访问这些对象,则最好使用shared_ptr的数组/向量/容器,因为这会使容器“折叠” ”可以说是shared_ptr概念。 This has the benefit that, when the object is removed from the container, it will not be immediately deallocated, and vice-versa with the shared pointers referencing it. 这样做的好处是,当从容器中删除对象时,将不会立即释放该对象,反之亦然,引用该对象的共享指针也是如此。

The downside of using a container of shared_ptrs is that it makes pointer math slightly more difficult since you are, in effect, working with a kind of pointer to a pointer. 使用shared_ptrs容器的缺点是,由于实际上使用的是指向指针的指针,因此指针数学变得稍微困难​​些。

You are expected to use shared pointers in only two ways: 您应该仅以两种方式使用共享指针:

1) When you create a new object, 1)创建新对象时,

std::shared_ptr<something> ptr(new something);

2) When you copy a shared pointer to another. 2)当您将共享指针复制到另一个指针时。

std::shared_ptr<something> copy(ptr);

So, if you create an object in an array, it won't fit the shared pointer scheme. 因此,如果您在数组中创建对象,则它不适合共享指针方案。

If you want to save an object allocated using a shared pointer in a vector, then you've got to save its shared pointer: 如果要在向量中保存使用共享指针分配的对象,则必须保存其共享指针:

std::vector<std::shared_ptr<something> > my_vector;

my_vector.push_back(new something);

When you clear your vector, all the pointers get cleared and thus objects that were only referenced by the vector get deleted: 清除向量时,所有指针都将清除,因此仅由向量引用的对象将被删除:

my_vector.clear();  // do "delete something" as required

As a side note, you say "more efficient" in your question... Shared pointers are not more efficient and they are not unlikely to create more code in your software than you would otherwise think of. 附带说明一下,您在问题中说“更有效” ...共享指针并不是更有效,并且它们在软件中创建的代码的可能性也不会比您想象的要多。

One very important point in C++ are exceptions. C ++中非常重要的一点是例外。 Objects saved in smart pointers (unique_ptr works too in that case) will automatically get deleted on exceptions. 保存在智能指针中的对象(在这种情况下,unique_ptr也起作用)将在异常时自动删除。 This is very important. 这个非常重要。 For example: 例如:

std::shared_ptr<something> ptr(new something);

...
if(this_is_true) throw std::logic_error("something's wrong");
...

In the code above, the pointer ptr automatically gets deleted before the throw returns. 在上面的代码中,指针ptr在抛出ptr之前自动被删除。 This is not what I would call more efficient, but much better in terms of cleanliness. 这不是我所说的更有效,但是在清洁度方面要好得多。 If you call a function that can throw (ie another new for example) then it becomes very tedious to handle each call (ie you'd need to have a try/catch around every single call and the catch would have to delete the pointers and then rethrow.) 如果您调用一个可以抛出的函数(例如,另一个new函数),则处理每个调用将变得非常乏味(即,您需要在每次调用中都进行一次try / catch,并且catch必须删除指针并然后重新抛出。)

So in that sense, it is efficient. 因此从某种意义上讲,它是有效的。 However, in terms of speed of execution, it is probably not any faster (or slower) than not using shared pointers. 但是,就执行速度而言,它可能比不使用共享指针快(或慢)。

It's possible for pointers to subobjects - array elements or object members - to share ownership with pointers to the whole object. 指向子对象(数组元素或对象成员)的指针可能与指向整个对象的指针共享所有权。 You create shared_ptr s to subobjects with the template constructor: 使用模板构造函数为子对象创建shared_ptr

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

It accepts a shared_ptr of any type, and a pointer (possibly completely unrelated) to the target type. 它接受任何类型的shared_ptr ,以及指向目标类型的指针(可能完全不相关)。 The constructed shared_ptr shares ownership with the source object r but when dereferenced points at ptr . 构造的shared_ptr与源对象r共享所有权,但是在取消引用时指向ptr

For example, create a pointer to the third array element of a std::array : 例如,创建一个指向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);

or to an object's data member: 或对象的数据成员:

struct foo {
  int i;
};
auto some_foo = std::make_shared<foo>();
auto foo_member = std::shared_ptr<int>(some_foo, &some_foo->i);

It's a shame there's no handy type-deducing "make" function like std::make_shared for this, it's annoying to explicitly specify the type of the subobject. 可惜没有像std::make_shared这样方便的类型推断“ make”功能,明确指定子对象的类型很烦人。 Maybe we should write our own: 也许我们应该自己写:

template <typename Object, typename SubObject>
inline std::shared_ptr<SubObject>
make_sub_ptr(const std::shared_ptr<Object>& c, SubObject* ptr) {
    return {c, ptr};
}

so we can simplify the earlier creations to: 因此我们可以将早期的创建简化为:

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 Coliru现场演示

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

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