Reputation: 1718
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
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