What I want to briefly talk about today is likely obvious to seasoned C++ programmers, but may be of benefit for the newcomers to the language and the STL: that is how to efficiently create std::vector of any number of elements of type T, whatever T may be. The code is short and sweet, so let’s jump right into it:
1 2 3 4 5 6 7 8 9 10 11 |
#include <vector> template<typename T, typename... A> inline auto make_N_of_T(std::size_t N, A&&... a) { std::vector<T> v; v.reserve(N); for(std::size_t i = 0; i < N; ++i) v.emplace_back(std::forward<A>(a)...); return v; } |
In lines #3 and #4 we define the creation function template ( inline because it’s likely to live in a header file and we don’t want to violate the ODR) that says make me N instances of T and use A as parameter(s) to T’s constructor (see parameter packs and fold expressions). Next we create an instance of std::vector<T> in line #6 and reserve enough space for N instances of T in line #7 (without actually constructing instances of T yet). Line #8 is self explanatory, and the efficiency magic happens in line #9. Instead of creating a temporary instance of T and calling .push_back we instead .emplace_back each instance of T, meaning we construct it in the memory previously reserved for the elements of the container in line #7. This way we avoid unnecessary copy or move constructors (which may not even be defined for type T).
Before C++11 and move semantics we would have been stuck with creating an instance of T, then copy constructing it into every element of std::vector<T>, like this:
1 2 |
std::size_t N = 42; vector<T> v(N, T{}); |
And don’t even get me started on having to return std::vector<T> from a function and how costly that would have been (again, prior to the magic of move semantics)! We’re in a brave new world…
P.S. I hope you’re all doing well and staying safe in this COVID-19 world! The situation has certainly put a strain on me and a dent in my blogging frequency. I hope to return to my normal post-or-more-a-week blogging frequency soon!