具有 STL 向量类型成员的类的复制内存

Copy memory of a class with STL vector type member

本文关键字:内存 复制 成员 STL 向量 类型 具有      更新时间:2023-10-16

对于下一个类的大小为 5 的向量,

struct Aclass
{
double x;
std::vector<double> y;
Aclass(){}
Aclass(double x, int ysize): x(x)
{
y.resize(ysize, x * ysize);
}
};

我想删除第二个元素:

void eraseEle()
{
std::vector<Aclass> v(5, Aclass(1, 3));

// Erase the 2nd element
{
std::vector<double>(0).swap(v[2].y);
// Copy the bits from &v[3] ~ &v[5] to &v[2]:
std::memmove(&v[2], &v[3], sizeof(Aclass) * (v.size() - 3));
v.resize(v.size() - 1);
}

// Print
for(int i = 0, iend = v.size(); i < iend; ++i)
{
std::cout << v[i].x << ", " << v[i].y[0] << "n";
}
}

该方法非常不标准。g++ 4.9.3 -O2编译它,但程序总是在std::memmove(...)崩溃。是因为 STL 向量的标头以某种方式受到保护,导致std::memmove()触发未定义的行为吗?

谢谢!

更深层次的答案

未定义行为的原因是.resize()v[4]中释放容器,因此之后,v[3]包含一个不指向任何内容的vector标头,在访问向量元素时引发未定义的行为。要真正使其正常工作,请添加

std::fill((char*)(&v.back().y), (char*)(&v.back().y) + 24, 0);

v.resize(v.size() - 1);之前.上面通过让最后一个元素(要擦除(包含不指向任何内容的vector来防止.resize()释放容器内存。

关于memmove的参考资料指出:

如果对象不是 TriviallyCopyable,则未指定 memmove 的行为,并且可能未定义

STL 矢量对象不是一个简单可复制的对象。

正如一条评论中所建议的,向量成员函数erase执行您想要执行的操作。

可简单复制的对象是类的对象,其中:

  • 每个复制构造函数都是微不足道的或删除
  • 每个移动构造函数都是微不足道或删除
  • 每个复制赋值运算符都是微不足道的或删除
  • 每个移动分配运算符都是微不足道或删除的
  • 至少一个复制构造函数
  • 、移动构造函数、复制赋值运算符或移动赋值运算符未删除
  • 普通的未删除析构函数

这意味着该类没有虚函数或虚拟基类。
TriviallyCopyable 对象的标量类型和数组也是 TriviallyCopyable,以及此类类型的 const 限定(但不是可变限定(版本。