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

shared_ptr in vector trouble - iterating and losing scope - getting corrupted data

本文关键字:范围 获取 损坏 数据 迭代 故障 shared 向量 ptr-      更新时间:2023-10-16

我对C++并不陌生,但我通常主要使用C#和其他托管语言,所以我不太熟悉共享指针等。

我基本上有一个共享ptrs到自定义类对象的三维映射(用于三维目的)。

这些shared_ptr位于地图中,并在整个项目中被引用,到目前为止效果良好。对于一个特定的功能,我将其中一些shared_ptr存储在一个向量中,以便稍后在代码中迭代,但这似乎是事情崩溃的地方。

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

正如我所说,我不太熟悉shared_ptrs,但我认为数据不会被破坏,因为实际对象是在创建三维地图的过程中创建的——而且,矢量还没有超出范围,因为我只在第二次运行for循环(有3个对象,因此有3次迭代)。

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

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

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->get()上表演的演员阵容有关吗?我看不到任何其他方法可以做到这一点,因为如果我没有强制转换,VS说它不能从ObjectClass*转换为shared_ptr,这对我来说也很困惑,因为我认为我有一个shared_ptrs的向量?。。

谢谢你抽出时间,如果有人能帮忙就太好了。

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

从中构造智能指针的原始指针将被传递以获得所有权。所有权必须是排他性的。使用它的方式是,两个shared_ptr将拥有同一个对象,导致过早删除,然后在某个时候进行双重删除,这两个都会让你进入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);

有战斗的机会。

好的,我发现了我的问题。

这在一定程度上与Balog-Pal所说的将shared_ptrs放在向量中有关,即使它们位于地图中,所以我改变了这一点,使向量包含指向shared_ptr的指针。尽管这可能仍然是一种糟糕的做法,但它解决了这个问题,尤其是当向量是局部的,并且在函数退出后失去了作用域时。

最初的向量方法是在我在函数中的某个位置对映射迭代器进行解引用时实现的,因此我决定将所有映射操作都放在迭代之外(因此将"特殊"对象存储在向量中,以便稍后迭代)。

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

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

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

感谢巴洛格的帮助,感谢它的回答和评论。