C++ 11 added convenient way to construct containers. It’s hard to argue that something like
looks much nicer than
It’s also nice that we can use the same approach to initialize std::array, std::map and many other containers generously offered by STL.
Since C++ promises zero cost abstractions, it would be reasonable to expect this convenience to come at no efficiency cost. But let’s double check, just in case. For our experiment, we’ll use a class to track special member function invocations
Looks like generated assembly for
comes with a surprise
note that
records 2 default constructor invocations which is expected, but there are also
that correspond to 2 copy constructors and 2 destructors, which seem completely unnecessary given that it’s moral equivalent
doesn’t involve these invocations
and records only 2 default constructors.
This also doesn’t happen for std::array and
results in what we’d expect
So why is this happening? Is this a bug? Let’s see what standard says
§ 11.6.4:
An object of type std::initializer_list is constructed from an initializer list as if the implementation generated and materialized (7.4) a prvalue of type “array of N const E”, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible (Clause 14) in the context of the initializer list. — end note ] [...]
So it’s not a bug and something to keep in mind in case initialization ends up on a hot path.
You can play more with this code using compiler explorer.
So there is no elision happening ? is it because of existing defs of the special members? Even copy init could be elided, at least that is what I thought but I might be wrong. I believe you are using 17+ here? thank you again for the post.