当我尝试复制它并将副本推送到同一向量中时,向量中的对象有时会被擦除

Posted

技术标签:

【中文标题】当我尝试复制它并将副本推送到同一向量中时,向量中的对象有时会被擦除【英文标题】:Object in a vector in an object in a vector sometimes gets erased when I try to copy it and push the copy in the same vector 【发布时间】:2018-01-23 17:35:43 【问题描述】:

对不起,标题有点乱,但我会试着解释一下:在顶层,我有一个对象向量(我们称之为vectorA)。现在我想在vectorA中复制其中一个对象(objectA),并将副本(objectA')推送到vectorA中。不需要深拷贝拷贝构造函数,因为对象只包含简单的变量和其他对象(objectB)的一个向量(vectorB)。 一切都被正确复制,并且大部分时间都可以正常工作。但是不时地,在正确复制 objectA 后,当在 VectorA 中推送 objectA' 时,在 objectA 中,vectorB 中的第一个 objectB 的地址被设置为 NULL。

如图:

VectorA > ObjectA > VectorB > ObjectB(设置为 NULL)

简化代码:

for (auto &objectA: vectorA) 
   ClassA objectA' = objectA;
   // Everything is copied correctly, the references to every attribute are different
   vectorA.push_back(objectA');
   // Now it's messed up, the reference to the first objectB in vectorB in objectA is NULL

【问题讨论】:

在同一个循环中尝试增长您正在迭代的容器似乎很糟糕。或者,您可以创建一个临时向量,并在完成后将其附加到您的初始 vectorA 【参考方案1】:

如std::vector::push_back() documentation中所述:

如果新的 size() 大于 capacity() 则所有迭代器和引用(包括过去的迭代器)都将失效。否则只有过去的迭代器无效。

因此,首先,您不能使用对现有对象的引用,因为如果发生重定位,它们将失效,最后(即使新大小小于或等于容量并且没有发生重定位)您不能调用 push_back() 获取向量您正在使用基于范围的 for 循环,因为它隐式使用了过去的迭代器。详情可见here

因此可能的解决方案是使用临时向量:

decltype(vectorA) tempVector;
for (auto &objectA: vectorA) 
   tempVector.push_back(objectA);

using moveIt = std::move_iterator<decltype(vectorA)::iterator>;
vectorA.insert( vectorA.end(), moveIt( tempVector.begin() ), moveIt( tempVector.end() ) );

注意:变量标识符只能使用字母、数字(不作为第一个符号)和下划线,因此objectA' 不是有效标识符。

【讨论】:

没错,我在简化代码中犯了一个错误。但我没有在我的真实代码中做到这一点。我遇到的真正问题在我的文字中进行了解释。 @H.Sch 我已经告诉过你你有什么问题 - a) 对象可以被重新定位并且引用会被 push_back() 和 b) 你不能在范围内使用 push_back()循环你正在迭代的向量。 您也可以在进入解决方案循环之前tempVector.reserve(vectorA.size()); 以防止重新分配。 @JustinRandall 没用

以上是关于当我尝试复制它并将副本推送到同一向量中时,向量中的对象有时会被擦除的主要内容,如果未能解决你的问题,请参考以下文章

在向量中推送结构会覆盖时间分量

c++ 将类成员推送到向量的正确方法

shared_ptr 未能推送到向量

推送到成员向量时的段错误

最好用正确的值实例化对象然后推送到向量,或者实例化,推送到向量然后设置正确的值?

将字符串转换为双精度,然后将其推送到 While 循环中的向量