user2961927
user2961927

Reputation: 1718

Copy memory of a class with STL vector type member

For a vector of size 5 of the following class,

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

I want to erase the 2nd element:

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";
  }
}

The method is quite nonstandard. g++ 4.9.3 -O2 compiles it but the program always crashes at std::memmove(...). Is it because the header of a STL vector is protected in some way that leads std::memmove() to trigger undefined behavior?

Thank you!

A deeper answer:

The reason for undefined behavior is that .resize() releases the container in v[4], so afterwards, v[3] contains a vector header that points to nothing, raising undefined behavior when accessing vector elements. To really make it work, add

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

before v.resize(v.size() - 1);. The above prevents .resize() releasing the container memory by letting the last element (to be erased) contain a vector that points to nothing.

Upvotes: 1

Views: 209

Answers (1)

P.W
P.W

Reputation: 26800

The reference on memmove states that:

If the objects are not TriviallyCopyable, the behavior of memmove is not specified and may be undefined

And STL vector object is not a trivially-copyable object.

As suggested in one comment, the vector member function erase does what you want to do.

Trivially-copyable objects are objects of classes where:

  • Every copy constructor is trivial or deleted
  • Every move constructor is trivial or deleted
  • Every copy assignment operator is trivial or deleted
  • Every move assignment operator is trivial or deleted
  • at least one copy constructor, move constructor, copy assignment operator, or move assignment operator is non-deleted
  • Trivial non-deleted destructor

This implies that the class has no virtual functions or virtual base classes.
Scalar types and arrays of TriviallyCopyable objects are TriviallyCopyable as well, as well as the const-qualified (but not volatile-qualified) versions of such types.

Upvotes: 2

Related Questions