C++ 矢量擦除函数删除错误对象
我有一个向量声明为:C++ 矢量擦除函数删除错误对象,c++,vector,stdvector,C++,Vector,Stdvector,我有一个向量声明为: vector<Curve> workingSet; 矢量工作集; Curve是我创建的一个类,它包含一个字符串“name”和一个由构造函数动态分配的结构数组 我有一个循环,应该从向量中删除2项(共4项) vector<Curve>::iterator it = workingSet.begin(); //remove tbi's children from the working set for ( ; it != work
vector<Curve> workingSet;
矢量工作集;
Curve是我创建的一个类,它包含一个字符串“name”和一个由构造函数动态分配的结构数组
我有一个循环,应该从向量中删除2项(共4项)
vector<Curve>::iterator it = workingSet.begin();
//remove tbi's children from the working set
for ( ; it != workingSet.end();){
if (it->thisName == tbi.childAName ||it->thisName == tbi.childBName)
it= workingSet.erase(it);
else
++it;
}
vector::iterator it=workingSet.begin();
//从工作集中删除tbi的子项
for(;it!=workingSet.end();){
如果(it->thisName==tbi.childAName | | it->thisName==tbi.childBName)
它=工作集。擦除(它);
其他的
++它;
}
当调试器到达.erase(it)调用时,我可以看到“it”迭代器指向向量中的曲线2。这是好的;我希望从向量中删除曲线2
vector<Curve>::iterator it = workingSet.begin();
//remove tbi's children from the working set
for ( ; it != workingSet.end();){
if (it->thisName == tbi.childAName ||it->thisName == tbi.childBName)
it= workingSet.erase(it);
else
++it;
}
然后,调试器将我带到析构函数(我在那里有一个断点),它大概应该是销毁曲线2。但是当我看这只手表时,我可以看到被破坏的曲线是曲线4!析构函数然后根据需要对对象中的数组执行“delete[]”操作,并将数组指针设置为NULL
当调试器返回程序,完成erase()调用后,我可以看到向量2已从数组中删除,曲线4仍然存在。曲线4的数组指针仍然指向与以前相同的位置,但内存已被释放,数组包含垃圾
有人能提出为什么曲线4被弄乱了吗
注意:(1)curve类有一个复制构造函数,它执行“深度”复制。
注:(2)这门课/课程的内容比我在这里提到的还要多
顺便说一句,根据调试器,曲线2和曲线4中的数组指针指向不同的位置并包含不同的值
编辑:我现在已经实现了复制分配。现在,正确的项似乎正在从向量中删除,但仍在调用错误的析构函数!但是,当调试器返回到数组时,曲线4仍然完好无损。当从向量中删除一个项时,它后面的所有元素都向前移动以填充空白。如果您的编译器还不支持
move
,那么可以通过复制所有元素来完成,并且向量中的最后一项(现在复制到它之前的项)是重复项,将被删除
至少它应该是这样工作的。在我看来,vector::erase不能用于本地构造的非平凡数据类型的向量(不是在堆上构造的对象,我现在不知道正确的名称)。我有与您描述的完全相同的行为,最后一个元素被销毁两次(如果您的对象具有由析构函数释放的内存,则特别危险),并且您删除的元素永远不会被销毁。我不知道为什么会发生这种情况,但这是一个值得警惕的陷阱 以下是解决此问题的一种方法:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class MyClass
{
public:
int *x;
MyClass(int x)
{
cout << "MyClass Constructor " << x << endl;
this->x = new int(x);
}
MyClass(const MyClass& obj)
{
this->x = new int(*obj.x);
cout << "copy constructor " << *this->x << endl;
}
~MyClass()
{
cout << "MyClass Destructor " << *x << endl;
delete x;
}
};
int main(int argc, char* argv[])
{
// incorrect
vector<MyClass> bad_vect;
for(int i=0;i<3;i++){
bad_vect.push_back(MyClass(i));
// causes a bunch of copying to happen.
// std::move does not seem to fix this either
// but in the end everything gets constructed as we'd like
}
cout << " ---- " << endl;
bad_vect.erase(bad_vect.begin() + 1); // we expect this to remove item with x = 1 and destruct it.
// but it does NOT do that, it does remove the item with x=1 from the vector
// but it destructs the last item in the vector, with x=2, clearly
// not what we want. The destructor for object with x=1 never gets called
// and the destructor for the last item gets called twice.
// The first time with x=2 and since that memory is freed, the 2nd time
// it prints garbage. Strangely the double-free doesn't crash the prog
// but I wouldn't count on that all the time.
// Seems some parts of STL have pitfalls with locally constructed objects
cout << " ------------ " << endl;
// below fixes this
vector<unique_ptr<MyClass> >vect;
for(int i=0;i<3;i++){
unique_ptr<MyClass> ptr(new MyClass(i));
vect.push_back( move( ptr )); // move is required since unique_ptr can only have one owner
// or the single one-liner below
//vect.push_back( move( unique_ptr<MyClass>(new MyClass(i)) ));
}
// the above prints out MyClass Constructor 0,1,2, etc
vect.erase(vect.begin() + 1); // remove the 2nd element, ie with x=1
// the above prints out MyClass Destructor 1, which is what we want
for(auto& v : vect){
cout << *(v->x) << endl;
} // prints out 0 and 2
return 0; // since we're using smart pointers, the destructors for the
// remaining 2 objects are called. You could use regular pointers
// but you would have to manually delete everything. shared_ptr
// also works and you don't need the move(), but with a bit more overhead
}
#包括
#包括
#包括
使用名称空间std;
类MyClass
{
公众:
int*x;
MyClass(int x)
{
你能不能提供一个可编译的最小示例来说明这个问题?你的口头描述没有多大帮助。无论如何:看看擦除/删除习惯用法。我们有很多问题都是这样回答的。另外一件事:你只提到了一个复制ctor,你也实现了复制分配吗?我还没有实现复制分配我现在就这么做,然后再回复你。展示你描述的行为的最小可编译示例。我观察到同样的问题。你使用了哪种编译器?