向量问题中的 shared_ptr - 迭代和丢失范围 - 获取损坏的数据

Posted

技术标签:

【中文标题】向量问题中的 shared_ptr - 迭代和丢失范围 - 获取损坏的数据【英文标题】:shared_ptr in vector trouble - iterating and losing scope - getting corrupted data 【发布时间】:2013-06-28 15:06:18 【问题描述】:

我对 C++ 并不陌生,但我通常主要使用 C# 和其他托管语言工作,因此我不太精通共享指针等。

我基本上有一个 shared_ptrs 到自定义类对象的 3 维映射(用于 3d 目的)。

这些 shared_ptrs 存在于地图中,并在整个项目中被引用,到目前为止一切都很好。对于特定的功能,我将其中一些 shared_ptrs 存储在一个向量中,以便稍后在代码中进行迭代,但这似乎是事情发生故障的地方。

假设我有 100 个这样的对象,它们的指针存储在 3d 地图中,其中 3 个被添加到向量中,因为它们具有特殊的功能属性。当我遍历向量时,我在这 3 个对象上调用函数。这一切正常,直到 for 循环(用于迭代)在向量的元素 [1] 上第二次运行,此时元素 [0] 充满了损坏的数据(但元素 [1] 需要访问元素 [0 ] 来执行其中一项功能),这就是我得到错误的地方。

正如我所说,我对 shared_ptrs 不是很精通,但我认为数据不会被破坏,因为实际对象是在创建 3 维地图时创建的——而且,向量还没有已经超出范围了,因为我只是在 for 循环的第二次运行(有 3 个对象和 3 次迭代)。

我知道我一定是做错了什么,但我不知道如何进一步调试 - 基本上当我单步执行代码时,如果我查看元素 [0],它会进入 for 循环的第二次运行向量中的shared_ptr(使用VS)全部损坏。

这是代码的循环,您可以看到。向量是在此代码所在类的构造函数中创建的,而映射(创建 shared_ptrs 和对象的位置)在应用程序的主类中。此外,getAdjacent 将 objA 和 objB 作为指针,因此将相邻对象的数据“填充”到 objB 到 objA:

for(vector<shared_ptr<ObjectClass>>::iterator iterator = objects.begin(); iterator != objects.end(); iterator++)

    shared_ptr<ObjectClass> objA = (shared_ptr<ObjectClass>) iterator->get();

    shared_ptr<ObjectClass> objB;

    m_3DMap->getAdjacent(objA, objB);

    objA->move(objB);

这可能与我在iterator-&gt;get() 上的演员阵容有关吗?我看不到任何其他方法可以做到这一点,因为如果我没有那个演员,VS 说它 无法从 ObjectClass* 转换为 shared_ptr 这对我来说也很困惑,因为我认为我有一个 shared_ptrs 的向量?..

感谢您的宝贵时间,如果有人能提供帮助,那就太好了。

【问题讨论】:

您应该避免在模板上使用&gt;&gt;。一些编译器会将其解释为shift right。顺便说一句:) 【参考方案1】:

对于初学者,您应该很少在 shared_ptr 上调用 get()。并且使用该指针来初始化另一个 shared_ptr 你永远不能这样做。

您构造智能指针的原始指针被传递给所有权。所有权必须是排他的。您使用它的方式是,两个 shared_ptrs 将拥有同一个对象,从而导致过早删除,然后在某些时候进行双重删除,两者都将您置于 UB 领域。

这比你原来的要好一些,但是如果没有看到代码,getAdjacent 也有可能在某种程度上被破坏了。

for(auto i = objects.begin(); i != objects.end(); ++i)

   const auto&  objA = *i;
   shared_ptr<ObjectClass> objB;
   m_3DMap->getAdjacent(objA, objB);
   objA->move(objB);

getAdjacent 的签名应该类似于

void getAdjacent(shared_ptr<ObjectClass> const& objA, shared_ptr<ObjectClass>& objB);

有战斗的机会。

【讨论】:

啊,好吧,我明白你的意思了。解决这个问题的更好方法是什么(而不是试图让我的(糟糕的)实现可行)?我的主要问题是所有这些对象都在 3-d 地图中,并且都是 shared_ptr。我想要一个较小的这些对象列表(基本上是当它们将状态从“正常”更改为“特殊”时),这样当我迭代它们时它是 o(n) (而不是遍历整个地图检查它们是否是'特殊”与否。任何帮助将不胜感激。【参考方案2】:

好的,我找到了我遇到的问题。

部分原因是 Balog Pal 所说的将 shared_ptrs 放在一个向量中,即使它们位于一个映射中,所以我更改了这一点,以便向量保存指向 shared_ptrs 的指针。虽然这可能仍然是不好的做法,但它解决了这个问题 - 特别是因为向量是本地的并且在函数退出后失去了作用域。

最初的向量方法是在函数中某处对我的地图迭代器进行取消引用时实现的,因此我决定将所有地图操作留在迭代之外(因此将“特殊”对象存储在要迭代的向量中稍后)。

我现在更改了实现以消除这种低效率,因为我的操作函数现在返回一个新的地图迭代器,从而解决了这个问题。

如果错误消息更有帮助那就太好了,因为我花了一些时间才意识到迭代器变得无效,因为我有一个 insert() 埋在调用的函数之一中 '特殊的'对象。

虽然这个答案并没有真正回答我提出的确切问题,但它回答了整个问题以及为什么我以我在问题中的方式设计函数。

感谢 Balog 和 itwasntpete 提供的答案和 cmets 的帮助。

【讨论】:

以上是关于向量问题中的 shared_ptr - 迭代和丢失范围 - 获取损坏的数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失现有数据的情况下调整 std::vector 的大小?

抽象类的 shared_ptr 向量到副本向量

存储 std::shared_ptr<Foo> 的向量,其中 Foo 是模板类

用于将 shared_ptr 向量填充到基础和派生对象的函数模板

shared_ptr 未能推送到向量

识别已将哪个基类 shared_ptr 传递到超类 shared_ptr 向量中