为何C++中vector.erase()行为不符合预期?
关于vector::erase的析构函数调用疑惑
我写了个测试vector::erase特性的程序,定义了MyClass0类,构造和析构时会打印信息。接着创建了包含4个MyClass0对象的vector,执行vec0.erase(vec0.begin() + 1)删除第二个元素时,我预期输出GoodBye From 2,但实际输出的是GoodBye From 4,看起来vector第四个元素的析构函数被提前调用了(它本该在main结束时才析构)。
测试代码
#include <iostream> #include <vector> using std::cout; using std::endl; class MyClass0 { public: MyClass0(int i_i_) : i_(i_i_) { cout << "Hello From " << this->i_ << endl; } ~MyClass0() { cout << "GoodBye From " << this->i_ << endl; } std::string MyToString() { return std::string("This is ") + std::to_string(this->i_); } private: int i_; }; int main() { std::vector<MyClass0> vec0 = { MyClass0(1), MyClass0(2), MyClass0(3), MyClass0(4) }; cout << endl << "Before erasing..." << endl; vec0.erase(vec0.begin() + 1); cout << "After erase" << endl << endl; return 0; }
运行输出
Hello From 1 Hello From 2 Hello From 3 Hello From 4 GoodBye From 4 GoodBye From 3 GoodBye From 2 GoodBye From 1 Before erasing... GoodBye From 4 After erase GoodBye From 1 GoodBye From 3 GoodBye From 4
问题原因解析
初始化阶段的临时对象析构:
用初始化列表{MyClass0(1), ...}创建vector时,会先构造4个临时MyClass0对象(对应输出里的前4个Hello From),随后vector会把这些临时对象拷贝到自己的内部存储中,临时对象完成使命后被依次析构(对应输出里的GoodBye From 4、3、2、1)。此时vector内部存储的是4个拷贝后的对象,i_值分别为1、2、3、4。erase操作的元素移动与析构:
执行erase(vec0.begin()+1)删除第二个元素时,vector会将删除位置之后的元素(第三个、第四个)依次向前移动一个位置,来填补被删除的空缺:- 第三个元素(
i_=3)移动到第二个位置 - 第四个元素(
i_=4)移动到第三个位置
移动完成后,vector的大小从4减为3,原来的第四个位置的对象就变成了多余的,会被析构。由于你的MyClass0没有自定义移动/拷贝构造函数,编译器生成的默认版本只会简单复制i_的值,所以这个被析构的对象的i_还是4,因此输出GoodBye From 4。
而你预期的第二个元素(i_=2),其实已经被第三个元素覆盖了——它的析构是在被移动操作覆盖时发生的,但因为没有自定义拷贝/移动构造,你看不到这个过程的输出,只能看到最后多余元素的析构。
- 第三个元素(
main结束时的vector对象析构:
main函数结束时,vector中剩下的三个对象(i_=1、3、4)会被依次析构,对应输出最后的三行GoodBye From。
内容的提问来源于stack exchange,提问作者Meysam
相关产品推荐
相关产品推荐

