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