In C++11, what is the cheapest way to create a std::vector< T > with a bunch of statically known T elements (in terms of the number of special member functions of T invoked)?

In other words, which of the blocks in the below program produces the fewest lines of output:

#include <iostream> #include <vector> struct S { S() { std::cout << " default ctor

"; } S(int) { std::cout << " int ctor

"; } S(S const &) { std::cout << " copy ctor

"; } S(S &&) { std::cout << " move ctor

"; } ~S() { std::cout << " dtor

"; } void operator =(S const &) { std::cout << " copy assignment

"; } void operator =(S &&) { std::cout << " move assignment

"; } }; int main() { { std::cout << "A1:

"; std::vector<S> s { S(), S(), S() }; } { std::cout << "A2:

"; std::vector<S> s { {}, {}, {} }; } { std::cout << "A3:

"; std::vector<S> s { 0, 0, 0 }; } { std::cout << "B1:

"; std::vector<S> s; s.reserve(3); s.push_back(S()); s.push_back(S()); s.push_back(S()); } { std::cout << "B2:

"; std::vector<S> s; s.reserve(3); s.push_back({}); s.push_back({}); s.push_back({}); } { std::cout << "B3:

"; std::vector<S> s; s.reserve(3); s.push_back(0); s.push_back(0); s.push_back(0); } { std::cout << "C1:

"; std::vector<S> s; s.reserve(3); s.emplace_back(S()); s.emplace_back(S()); s.emplace_back(S()); } // { // std::cout << "C2:

"; // std::vector<S> s; // s.reserve(3); // s.emplace_back({}); // s.emplace_back({}); // s.emplace_back({}); // } { std::cout << "C3:

"; std::vector<S> s; s.reserve(3); s.emplace_back(0); s.emplace_back(0); s.emplace_back(0); } }

(Of course, each block needs at least three “ dtor ” lines when its s goes out of scope, so keep those out of the count.)

What might come as a surprise is that the A variants using an initializer list, though short and sweet, are rather heavy: Each one needs three constructors for the three elements of the initializer list (“ default ctor ” for A1 and A2 , “ int ctor ” for A3 ), three copy constructors to copy the elements from the initializer list into the vector, and three destructors when destroying the initializer list. Nine calls to special member functions overall.

That is just as expensive as the B variants. (The difference being the order in which the special member functions are called for the individual elements.) However, the advantage of all three B variants is that they use the move constructor instead of the copy constructor to pass the temporary S instances into the vector.

(If you had hoped that the A variants would use the move constructors instead of the copy constructors, too: that does not work, as initializer lists only offer const access to their members.)

Variant C1 is not any different from variant B1 . Still nine calls overall (employing the move constructor).

Variant C3 , finally, is better: Although it looks more expensive to pass “wrong” int arguments that first need to be converted into proper S instances, the big benefit here is that those “ int ctor ” calls can directly instantiate the vector elements—no construction of temporary S instances, no copy or move constructors, no destruction of temporaries. Just three constructor calls overall.

(And variant C2 is commented out for good reason; there is just no way to tell emplace_back to instantiate an element directly into the vector through a default constructor call. But then again, most of the time what you want to put into the vector are not default-constructed elements, anyway.)