1

When the capacity of an ::std::vector<T> is reached and an additional element is inserted, it appears that ::std::vector<T> copy-constructs the data after reallocating a larger portion of memory.

This seems horribly inefficient if for instance we have a vector<vector<vector<int>>> because the entire content must be deep-copied. If move semantics were exploited the overhead would (typically) be constant per entry, as opposed to unbounded.

Question(s)

  1. Why does it do this?
  2. Can I force it to ::std::move the contents?

Example

To analyse this, I implemented a small wrapper type DataPrinter that holds a char and basically couts each construction/destruction. And I get this:

::std::vector<DataPrinter> v;
::std::cout << "emplacing a\n";
v.emplace_back('a');
::std::cout << "emplacing b\n";
v.emplace_back('b');
::std::cout << "emplacing c\n";
v.emplace_back('c');

emplacing a
[0x60200000eff0] DataPrinter(a)
emplacing b
[0x60200000efd1] DataPrinter(b)
[0x60200000efd0] DataPrinter(DataPrinter[a]const &)
[0x60200000eff0] ~DataPrinter[a]()
emplacing c
[0x60200000efb2] DataPrinter(c)
[0x60200000efb0] DataPrinter(DataPrinter[a]const &)
[0x60200000efb1] DataPrinter(DataPrinter[b]const &)
[0x60200000efd0] ~DataPrinter[a]()
[0x60200000efd1] ~DataPrinter[b]()

I am building with clang++ 3.5.0-10 and -fsanitize=address -std=c++1z.

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • 3
    does `DataPrinter` have a `noexcept` move constructor ? – Piotr Skotnicki Nov 24 '16 at 12:05
  • Ah, no it isn't `noexcept` but it has a move constructor. Checking ... – bitmask Nov 24 '16 at 12:06
  • 1
    Yes, that was it. If I add `noexcept` to all ctors it moves content. Thanks. Do you have an explanation why `noexcept` changes this? (-> answer?) – bitmask Nov 24 '16 at 12:08
  • 1
    Because the reallocation isn't allowed to throw. – Hatted Rooster Nov 24 '16 at 12:09
  • @GillBates: But the const-ref copy-ctor wasn't `noexcept` either. So it's basically the same, isn't it? – bitmask Nov 24 '16 at 12:10
  • @bitmask It's just the move constructor which is not allowed to throw. – TartanLlama Nov 24 '16 at 12:11
  • @LogicStuff Yep, that's a dupe. Couldn't find it with the search before I asked. Voted to close. – bitmask Nov 24 '16 at 12:13
  • 4
    @bitmask it goes like this, if a copy-construction throws an exception, the original vector is unchanged (good). if a relocation fails in the middle due to a move construction failure of a single element, then the original vector is already modified. to restore its original state, you'd have to reverse the operation by move constructing the elements back, which can again throw (bad), see [`std::move_if_noexcept`](http://en.cppreference.com/w/cpp/utility/move_if_noexcept) for a reference. that's why a copy-constructor is allowed to throw – Piotr Skotnicki Nov 24 '16 at 12:13
  • @PiotrSkotnicki That actually makes a whole lot of sense, thank you for the explanation! – bitmask Nov 24 '16 at 12:15

0 Answers0