Reputation: 8441
I was trying to understand the following behaviour:
#include <vector>
#include <iterator>
struct Foo {
Foo(int a) : a_ {a} {}
const int a_; // Note the const
};
int main(int argc, char **argv) {
std::vector<Foo> v1 {Foo {0}};
std::vector<Foo> v2 {Foo {1}};
auto first = std::begin(v2);
auto last = std::end(v2);
for (; first != last; ++first) {
v1.push_back(*first); // Fine
}
//v1.insert(v1.begin(), first, last); // Does not compile
return 0;
}
It turns out the const
member of Foo
was implicitly deleting Foo
s copy-assignment operator, which std::vector::insert
used.
Why does std::vector::insert
need to copy assign while std::vector::push_back
copy constructs? Does this mean it can be more efficient to manually concatenate two vectors? This is using LLVM.
Upvotes: 6
Views: 2166
Reputation:
There is no reason why an assignment operator would be required, logically speaking. The insert
operation can be implemented entirely by moving any existing element vec[x]
to vec[x+1]
by using (roughly) vec[x+1].~T(); new(&vec[x+1]) T(std::move(vec[x]));
in a loop to destroy an existing element, and use in-place construction to move the previous element forward.
However, a more natural approach to write this, which in well-designed classes is typically at least as efficient if not more so too, is to use assignment for that: vec[x+1] = std::move(vec[x]);
. An easy example of when it can be more efficient is if the construction and destruction of the vector's elements involves allocating and deallocating memory: using assignment easily bypasses that.
A decision was made that allowing vectors to use assignment operators has more benefits than drawbacks. Your class is unusual, and your class happens not to benefit from this decision. It's unfortunate, but there's no way of designing a vector that's perfect for every use case.
Upvotes: 8
Reputation: 9466
To insert an element into the vector, if it's not the end, you should move all the tail elements
[1][2][3][4][5]
| | | \ \
[1][2][3][6][4][5]
so, a move or copy constructor is required.
http://en.cppreference.com/w/cpp/container/vector/insert
You still can convert the loop into
copy(first, last, back_insterter(v1))
Upvotes: 2