Passing a string by value, reference and rvalue
Let's analyze your code and suppose long strings (without applied SSO):
void add(std::string msg) {
msg += "world";
}
void StringCreation() {
add(std::string("hello "));
}
Here, a converting constructor (ConvC) from the string literal is called first to initialize the temporary std::string("hello ")
. This temporary (an rvalue) is then used to initialize the parameter msg
by the move constructor (MC). However, the latter is very likely optimized away by copy elision. Finally, the operator +=
is called. Bottom line: 1x ConvC and 1x +=
.
void StringCopy() {
std::string msg("hello ");
add(msg);
}
Here, the parameter msg
is copy-initialized (by copy constructor - CC) by the lvalue argument msg
. Bottom line: 1x ConvC, 1x CC, and 1x +=
. In case of long strings, this is the slowest version, since copy involves dynamic memory allocations (the only case).
void StringMove() {
std::string msg("hello ");
add(std::move(msg));
}
Why is this slower than StringCreation
? Simply because there is an additional MC involved that initializes the parameter msg
. It cannot be elided, since the object msg
still exist after the call of add
. Just it is moved-from. Bottom line: 1x ConvC, 1x MC, 1x +=
.
void addRef(std::string& msg) {
msg += "world";
}
void StringReference() {
std::string msg("hello ");
addRef(msg);
}
Here, the operator +=
is applied to the referenced object, so there is no reason for any copy/move. Bottom line: 1x ConvC, 1x +=
. Same time as for StringCreation
.
void addRvalue(std::string&& msg) {
msg += "world";
}
void StringRvalue() {
std::string msg("hello ");
addRvalue(std::move(msg));
}
With Clang, the time is same as for StringReference
. With GCC, the time is same as for StringMove
. In fact, I don't have an explanation for this behavior for now. (It seems to me that GCC is creating some additional temporary initialized by MC. However, I don't know why.)