【问题标题】:How to properly instantiate an object in one container and store a shared_ptr to it in a separate container?如何在一个容器中正确实例化一个对象并将 shared_ptr 存储在一个单独的容器中?
【发布时间】:2021-03-04 10:47:43
【问题描述】:

假设我们有一个存储一些数据的结构或类:

struct Foo
{
    int bar;
}

还假设我想存储两个单独的向量;一个包含Foo 的实际实例和shared_ptr 的向量,这将允许我任意访问该数据:

std::vector<Foo> data; // Where the data actually is

std::vector<std::shared_ptr<Foo>> ptr_data; // A set of pointers to the elements in data

如何将一个元素插入到 data 向量中,然后添加一个指向该元素的相应 shared_ptr 我希望实际数据的唯一副本存在于data 向量。

我不相信我可以使用make_shared,因为我似乎找不到任何关于如何控制数据存储位置的文档。并且不应该在函数超出范围时收集匿名数据吗?

void addDataToVectors() 
{
    ptr_data.push_back(std::make_shared<Foo>( 20 )); // Can I put this into the data vector?
    // And shouldn't the data disappear as soon as this function ends?
}

我也试过这个:

void addDataToVectors() 
{
    data.push_back({ 20 }); // Add the instance to data
    // Attempt to create a shared pointer from the last address in data
    ptr_data.push_back(std::shared_ptr<Foo>(&data.back())); 
}

但这似乎不起作用。添加第一组数据及其指针是正确的,但ptr_data 向量中的每个后续push_back 似乎都会破坏除最后一个之外的所有条目。这种方法显然有问题,开始时感觉很糟糕。

对 STL 容器执行此操作的正确方法是什么?

【问题讨论】:

  • 没有合适的方法来做这样的事情。 std::vectorstd::shared_ptr 都不会按照您认为的方式工作。 shared_ptr 不指向存储在任何其他容器中的任何对象。 shared_ptr 存在的全部原因是它拥有对象,并且完全负责删除它。容器的全部原因是做同样的事情,但方式不同。除此之外,向量可以重新分配和移动它们的内容,这是一个完全不合逻辑的情况。选择一个,容器或 shared_ptr,但不能同时选择两者。
  • 您可以拥有两个指向相同对象的共享指针容器,也可以拥有两个指向相同容器对象的共享指针。
  • 一个对象只能有一个所有者(或共享所有者),因此当它的所有者被删除时,它只会被删除一次。容器拥有它们的对象,因此您不能将这些相同的对象赋予另一个所有者。你可以使用原始指针向量吗?只要您可以保证在对象向量被销毁后永远不会使用原始指针,那就没问题了。此外,您不能更改整数向量的内容,因为这会使您的原始指针无效。
  • 如果您使用shared_ptrs,那么两个向量都需要包含shared_ptrs 到相同的Foos。如果您使用原始指针,那么每次添加 Foo 时都需要检查向量是否重新分配,如果确实如此,请重建原始指针向量。
  • 另一种方法是忘记指针并将索引存储为std::vector&lt;std::size_t&gt; idx_data;

标签: c++ stl c++14 smart-pointers


【解决方案1】:

shared_ptr 确实表示“指向由其他人管理的对象”。 shared_ptr 的意思是“指向一个对象,当最后一个 shared_ptr 消失时,该对象将被删除。” vector 拥有它的元素。 shared_ptr 拥有它所指向的内容。一个对象不能有两个所有者,除非这些所有者有一个预先安排的合作协议,共享指针彼此之间有这个协议。

如果您想拥有std::vector&lt;Foo&gt; data,则将原始指针(或引用)传递给其元素,但需要注意的是,如果修改了vector,这些指针(或引用)可能会变得无效。这种方法不是最安全的方法,但在某些情况下,它已经足够好了。 或者,如果元素从未从 data 中删除,那么您可以将索引传递给 data 而不是指针。

如果你想拥有std::vector&lt;std::shared_ptr&lt;Foo&gt;&gt; ptr_data,那么在每个声称拥有这些对象的容器中使用共享指针或弱指针。也就是说,data 也是shared_ptrs 的向量。

void addDataToVectors() 
{
    auto ptr = std::make_shared<Foo>(20);
    data.push_back(ptr);
    ptr_data.push_back(ptr);
}

如果你玩混搭,你还不如玩gas-and-match。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-12
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    • 2013-02-19
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多