【问题标题】:Shared Pointer to an object in a vector指向向量中对象的共享指针
【发布时间】:2019-10-18 09:15:41
【问题描述】:

我试图弄清楚,如果您创建一个共享指针,该指针指向一个保存在向量中的对象,会发生什么。

代码如下所示:

class TestObject
{
public:
    int someTestData;
};

class Test
{
public:
    std::shared_ptr<TestObject> testPointer;

    std::shared_ptr<std::vector<TestObject>> getTestVector()
    {
        return testVector;
    }

private:
    std::shared_ptr<std::vector<TestObject>> testVector;
};

问题是,我既想支持对所有测试对象的快速迭代,又想提供指向向量中单个对象的共享指针。 但是现在我不知道如果向量中一个对象的最后一个共享ptr被删除会发生什么。

  • 对象是否从向量中移除?
  • 这会导致未定义的行为吗?
  • 如果这不起作用,我该如何归档我想要的行为?

编辑:

澄清一下,我需要什么:

我需要一个 MemoryManager 类,它有一个 CreateTestObject 方法,它创建一个新的 TestObject,将它存储在一个向量或其他支持快速迭代的容器中,并向新创建的对象返回某种 shared_ptr,以便该对象需要一个新的 TestObject 有一个引用。

现在我还需要 TestObject 的 shared_ptr 以便能够在最后一个 shared_ptr 超出范围时从存储它的容器中删除 TestObject,这样我就不会留下一个充满未使用的 TestObject 的向量.

【问题讨论】:

  • 您是否遗漏了部分代码?因为你的问题对我来说并不完全清楚
  • 请尝试澄清您的实际需求。
  • iirc 共享指针欠它指向的东西,当指针的生命周期到期时,你真的希望向量中的对象被销毁吗? (然后当向量的生命周期到期时,它将破坏已经破坏的对象,ub)
  • 您如何从std::vector 的对象中获取shared_ptr&lt;TestObject&gt;testVector 中的对象归 std::vector 所有。如果您使用这些地址创建shared_ptr,您几乎肯定只会导致未定义的行为。
  • @uneven_mark 我正在向量中创建对象,然后获取地址并创建共享 ptr 有没有办法归档我想要的行为?

标签: c++ vector shared-ptr


【解决方案1】:

很难知道最终会发生什么,因为您没有共享实际初始化testPointer 的代码。但您正在寻找的是一个 aliased std::shared_ptr:

testPointer = {testVector, &(*testVector)[0]};

从那时起,testPointer 指向向量的第一个元素,但与 testVector 共享向量本身的所有权,从而提供正确的语义。

请注意,这不会阻止向量重新分配其存储空间并使testPointer 在重新分配时悬空。

为了记录,尝试构造一个拥有元素本身的std::shared_ptr,如下:

testPointer.reset(&(*testVector)[0]); // Wrong!

... 必然会触发 UB,因为 std::vector 已经拥有其元素的唯一所有权,并且您无法让 std::vectorstd::shared_ptr 放弃所有权。

【讨论】:

    【解决方案2】:

    “我试图弄清楚,如果你创建一个共享指针,它指向一个保存在向量中的对象,会发生什么。”

    这是一个非常糟糕的主意,因为向量的任何元素的位置都可以通过向向量中添加或删除元素来改变。您实现的只是所有权的重复,这会破坏基本的 OOP 概念。

    对象是否从向量中移除?

    共享指针是对象的“所有者”,而向量也是所有者。所以它是概念性的破坏!

    这会导致未定义的行为吗?

    它仍然是未定义的,因为你会生成悬空点,因为 vector 可以移动它的对象。

    如果这不起作用,我该如何实现我想要的行为?

    您已经通过operator[] 快速访问并且您已经拥有“指针”,因为迭代器可以用作任何其他指针。

    【讨论】:

      【解决方案3】:

      您可以使用带有shared_ptr 的自定义删除器并使用boost::stable_vector 之类的容器来执行此操作:

      testVector.emplace_back();
      auto it = V.end()-1;
      auto deleter = [&testVector, it] (int*) {testVector.erase(it);};
      std::shared_ptr<TestObject> ptr(&testVector.back(), deleter);
      

      当对象的最后一个shared_ptr 超出范围时,它会将其从TestVector 中删除。但是请注意,这反过来不起作用:如果对象通过任何其他方式从TestVector 中删除(例如,TestVector 超出范围),这将触发未定义的行为,因此您有责任确保不会发生这种情况。另请注意,这不适用于std::vector,因为在调整向量大小时迭代器会失效。但是,您可以使用std::list,尽管这可能会比stable_vector 慢。

      这不是最干净的解决方案(因为如果你不小心,很可能会触发 UB),但是以探测方式执行此操作会涉及更多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-12
        • 2019-07-06
        • 1970-01-01
        相关资源
        最近更新 更多