Justin's answer on another question made an observation that I find very interesting but can't quite explain. Consider the following code:
std::vector<std::string> v;
v.push_back("Hello, world!"); // Doesn't call strlen.
v.emplace_back("Hello, world!"); // Calls strlen.
If you look at the assembly, emplace_back
generates a call to strlen
, whereas push_back
does not (tested in gcc 8.1 and clang 6.0 using -Ofast
).
Why is this happening? Why can't emplace_back
optimize out the strlen
call here? My initial thought was that push_back
is implicitly creating the std::string
before the function call (so the std::string
constructor is directly passed the string literal, which is optimally handled), whereas emplace_back
creates the std::string
after the function call (so the std::string
constructor is forwarded the string literal, which I presumed had decayed from a const char [N]
to a const char *
, thus requiring a strlen
call).
But emplace_back
takes a T&&
parameter, and my tests show that the string literal shouldn't be decaying to a pointer here. Clearly I'm overlooking something.
If you intend to call explicit constructors, then you need the power of emplace_back . If you want to call only implicit constructors, stick with the safety of push_back .
because emplace_back would construct the object immediately in the vector, while push_back , would first construct an anonymous object and then would copy it to the vector.
The strlen
call is in the out-of-line function body for the slow path; that function body must be valid for all arguments of type const char (&)[42]
(in your godbolt example), including arguments that did not originate from a string literal of 41 characters with no embedded nulls.
The fast path is inlined into foo
, and it does compute the length at compile time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With