I recently realized that the addition of move semantics in C++11 (or at least my implementation of it, Visual C++) has actively (and quite dramatically) broken one of my optimizations.
Consider the following code:
#include <vector>
int main()
{
typedef std::vector<std::vector<int> > LookupTable;
LookupTable values(100); // make a new table
values[0].push_back(1); // populate some entries
// Now clear the table but keep its buffers allocated for later use
values = LookupTable(values.size());
return values[0].capacity();
}
I followed this kind of pattern to perform container recycling: I would re-use the same container instead of destroying and recreating it, to avoid unnecessary heap deallocation and (immediate) reallocation.
On C++03, this worked fine -- that means this code used to return 1
, because the vectors were copied elementwise, while their underlying buffers were kept as-is. Consequently I could modify each inner vector knowing that it could use the same buffer as it had before.
On C++11, however, I noticed that this results in a move of the right-hand side onto the left-hand side, which performs an element-wise move-assignment to each vector on the left-hand side. This in turn causes the vector to discard its old buffer, suddenly reducing its capacity to zero. Consequently, my application now slows down considerably due to excess heap allocations/deallocations.
My question is: is this behavior a bug, or is it intentional? Is it even specified by the standard at all?
Update:
I just realized that correctness of this particular behavior may depend on whether or not a = A()
can invalidate iterators that point to the elements of a
. However, I don't know what the iterator invalidation rules for move-assignment are, so if you're aware of them it may be worth mentioning those in your answer.