代码之家  ›  专栏  ›  技术社区  ›  user2961927

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

c++
  •  1
  • user2961927  · 技术社区  · 7 年前

    对于一个大小为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(...) std::memmove() 触发未定义的行为?

    更深层次的回答 :

    .resize() 释放容器 v[4] ,所以后来, v[3] 包含 vector 指向nothing的头,在访问向量元素时引发未定义的行为。为了让它真正起作用,添加

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

    之前 v.resize(v.size() - 1); . 以上防止 .resize() 矢量 这说明什么都没有。

    1 回复  |  直到 5 年前
        1
  •  2
  •   P.W    7 年前

    这个 reference memmove 声明:

    如果对象不是平凡可复制的,那么memmove的行为就不会被指定,也可能是未定义的

    正如在一个注释中所建议的,向量成员函数 erase

    Trivially-copyable 对象是类的对象,其中:

    • 每个副本构造函数都是琐碎的或删除的
    • 每个移动构造函数都是琐碎的或删除的
    • 每个拷贝赋值操作符都是琐碎的或删除的
    • 至少有一个复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符未被删除
    • 普通非删除析构函数


    平凡可复制对象的标量类型和数组也是平凡可复制的,以及此类类型的常量限定(但不是volatile限定)版本。