在std::vector::erase()中自定义销毁过程



当我对'T'类型的向量调用erase函数时,会调用我调用erase((的范围后面的元素的析构函数。有没有办法自定义这种行为?如何确保正在擦除的元素的析构函数被调用?

示例程序

#include <iostream>
#include <vector>
enum type {
TYPE_DEFAULT,
TYPE0,
TYPE1,
TYPE2,
TYPE3,
TYPE4,
};
char str[][13] = {"TYPE_DEFAULT","TYPE0","TYPE1","TYPE2","TYPE3","TYPE4"};
struct temp {
type objType;
void printInfo() const {
std::cout << "nthis-->" << this;
std::cout << "nType-->" << str[objType]<<"n";
}
temp() {
objType = type::TYPE_DEFAULT;
std::cout << "n**Default Constructor**";
printInfo();
}
temp(const temp& obj) = default;
temp& operator=(const temp& obj) {
std::cout << "n**operator=**";
objType = obj.objType;
printInfo();
return *this;
}
~temp() {
std::cout << "n**Destructor**";
this->printInfo();
std::cout << "n";
}
};
int main() {
std::vector<temp> vec;
vec.resize(5);
for (int i=0; i < 5; i++) {
vec[i].objType = (type)(i+1);
}
std::cout <<"nPrinting vector before erase. Size->" << vec.size()<< "n";
for (const auto& x : vec) {
x.printInfo();
}
int start = 0;
int end = 2;
std::cout << "nGoing to call erase for vec[" << start << ","<< end << ")n";
vec.erase(vec.begin() + start, vec.begin() + end);
std::cout << "nErase has been invokedn";
std::cout << "nPrinting vector Info after erase. Size->"<<vec.size() << "n";
for (const auto& x : vec)
x.printInfo();
}

输出

**Default Constructor**
this-->0xf9c010
Type-->TYPE_DEFAULT
**Default Constructor**
this-->0xf9c014
Type-->TYPE_DEFAULT
**Default Constructor**
this-->0xf9c018
Type-->TYPE_DEFAULT
**Default Constructor**
this-->0xf9c01c
Type-->TYPE_DEFAULT
**Default Constructor**
this-->0xf9c020
Type-->TYPE_DEFAULT
Printing vector before erase. Size->5
this-->0xf9c010
Type-->TYPE0
this-->0xf9c014
Type-->TYPE1
this-->0xf9c018
Type-->TYPE2
this-->0xf9c01c
Type-->TYPE3
this-->0xf9c020
Type-->TYPE4
Going to call erase for vec[0,2)
**operator=**
this-->0xf9c010
Type-->TYPE2
**operator=**
this-->0xf9c014
Type-->TYPE3
**operator=**
this-->0xf9c018
Type-->TYPE4
**Destructor**
this-->0xf9c01c
Type-->TYPE3

**Destructor**
this-->0xf9c020
Type-->TYPE4

Erase has been invoked
Printing vector Info after erase. Size->3
this-->0xf9c010
Type-->TYPE2
this-->0xf9c014
Type-->TYPE3
this-->0xf9c018
Type-->TYPE4
**Destructor**
this-->0xf9c010
Type-->TYPE2

**Destructor**
this-->0xf9c014
Type-->TYPE3

**Destructor**
this-->0xf9c018
Type-->TYPE4

程序描述

在上面的程序中,我有一个名为temp的结构的向量(大小为5(。当我在范围[0,2(上调用erase时,会调用最后2个元素的析构函数。我需要做什么来调用前2个元素?

使用std::vector无法做到这一点。擦除将从std::vector中删除您想要的项目,但它可能不会破坏那些特定的对象。

如果绝对有必要调用前两个元素的析构函数,如果只在后面和前面插入和擦除,请考虑使用deque,如果不需要随机访问,则可以使用std::forward_list

p.S.std::vector对于除了后面以外的任何地方的插入和擦除都是可怕的,因为它必须移动插入/擦除项目前面的所有元素。

您不想销毁前两个元素,因为它们在擦除后仍然有效,所以这样做是没有意义的。它们的值已被赋值覆盖。也许您真正想要的是定义一个交换元素的移动分配操作符(实现移动分配的常见方式(。这最终会将前两个元素中的数据放入后两个元素,因此析构函数在销毁它们时会看到这些数据。

#include <vector>
#include <iostream>
class temp {
static int uid;
int id;
public:
temp() : id(++uid) {
std::cout << "default ctor for temp #" << id << " at " << this << std::endl; }
temp(temp &&a) : id(a.id) {
std::cout << "moving temp #" << id << " from " << &a << " to " << this << std::endl; 
a.id = -1; }
~temp() {
if (id >= 0)
std::cout << "destroying temp #" << id << " at " << this << std::endl;
else
std::cout << "destroying previously moved from temp at " << this << std::endl; }
temp &operator=(temp &&a) {
std::cout << "swapping temps #" << id << " and #" << a.id << " at " << this
<< " and " << &a << std::endl;
std::swap(id, a.id);
return *this; }
temp(const temp &) = delete;
temp &operator=(const temp &) = delete;
};
int temp::uid = 0;
int main() {
std::vector<temp>   v;
std::cout << "resize vector to 5" << std::endl;
v.resize(5);
std::cout << "erase first two elements" << std::endl;
v.erase(v.begin(), v.begin() + 2);
std::cout << "end -- destroying vector" << std::endl;
}

产生输出

resize vector to 5
default ctor for temp #1 at 0x5624ecff0280
default ctor for temp #2 at 0x5624ecff0284
default ctor for temp #3 at 0x5624ecff0288
default ctor for temp #4 at 0x5624ecff028c
default ctor for temp #5 at 0x5624ecff0290
erase first two elements
swapping temps #1 and #3 at 0x5624ecff0280 and 0x5624ecff0288
swapping temps #2 and #4 at 0x5624ecff0284 and 0x5624ecff028c
swapping temps #1 and #5 at 0x5624ecff0288 and 0x5624ecff0290
destroying temp #2 at 0x5624ecff028c
destroying temp #1 at 0x5624ecff0290
end -- destroying vector
destroying temp #3 at 0x5624ecff0280
destroying temp #4 at 0x5624ecff0284
destroying temp #5 at 0x5624ecff0288

您也可以将移动分配定义为销毁目标,然后从源移动(重新(构建目标。当您有这样一个move ctor或move赋值时,有必要以这样一种方式"标记"从对象中移出的对象,即析构函数知道它实际上不需要做任何事情。

最新更新