对于stl向量我有一个非常奇怪的问题,当我调用擦除方法时,如果有意义的话,会为正确的对象调用错误的析构函数。
我的代码看起来像这样:
for(vector<Category>::iterator iter = this->children.begin(); iter != this->children.end(); iter++)
{
if((*iter).item == item)
{
this->children.erase(iter);
return;
}
-------------------------
}
它只是一个简单的函数,它在向量中找到要搜索的项目的元素,并从向量中移除所述元素。我的问题是,当调用erase函数时,迭代器指向的对象被破坏,正在调用错误的析构函数。更具体地说,正在调用向量中最后一个元素的析构函数,而不是被删除的实际对象的析构函数。因此,内存将从错误的对象中移除,该对象仍将是向量中的元素,并且从向量中移除的实际对象仍然保持其所有内存的完整性。 对象的costructor如下所示:
Category::Category(const Category &from)
{
this->name = from.name;
for(vector<Category>::const_iterator iter = from.children.begin(); iter != from.children.end(); iter++)
this->children.push_back((*iter));
this->item = new QTreeWidgetItem;
}
析构函数
Category::~Category()
{
this->children.clear();
if(this->item != NULL)
{
QTreeWidgetItem* parent = this->item->parent();
if(parent != NULL) parent->removeChild(this->item);
delete this->item;
}
}
答案 0 :(得分:5)
从向量中删除元素时,将其后的每个元素(使用赋值运算符)复制到向量中的前一个点。一旦完成,矢量中的最后一个元素就被破坏了。这可能就是为什么你看到你的最后一个元素被破坏了。使用STL时的第一条规则是确保对象的复制语义正确。
您应该考虑编写赋值运算符:
Category & operator =(const Category & other);
虽然这可能不像听起来那么简单,但考虑对象会在向量中被复制和破坏多次。
答案 1 :(得分:0)
您可能应该使用标准算法。
我看到的主要问题是你的类的析构函数要求它的父矢量删除它。这可能不对,析构函数只有在向量已经删除它时才会发生。
std :: vector使用placement-new所以将直接调用你的析构函数。我不知道此时回到矢量会产生什么影响。
从析构函数中删除行if (parent != NULL ) parent->removeChild(this->item)
。这不是你想要的。
答案 2 :(得分:0)
这是预期的行为。在我的实现(我猜你的)上,当从一个向量中删除一个元素时,从n + 1到结尾的元素被分配到它中,最后一个元素被破坏。
如果您不希望发生这种情况,请使用std::list
。
演示:
#include <iostream>
#include <vector>
struct Category
{
int item;
Category(int n=0) : item(n) {}
~Category() { std::cout << "Category " << item << " destroyed\n"; }
};
int main()
{
std::vector<Category> children(3);
children[0] = Category(0);
children[1] = Category(1);
children[2] = Category(2);
int item = 0;
std::cout << " beginning the loop \n";
for( std::vector<Category>::iterator iter = children.begin();
iter != children.end(); ++iter)
{
if(iter->item == item)
{
children.erase(iter); // prints "Category 2 destroyed"!
break;
}
}
std::cout << " loop done \n";
} // this will print "Category 1 destroyed" and "Category 2 destroyed"
是的,显式erase
/ remove_if
比循环更具可读性。