Dagoberto Pires Dagoberto Pires - 3 days ago 6
C++ Question

Is the following case of std::move superfluous?

Is the following case of

std::move
superfluous?

std::string member;

obj(std::initializer_list<std::string> p_list)
: member {std::move(join(p_list))}
{}


This is the join function:

std::string join(string_initializer_list p_list) {
size_t size {};
for (auto const & s : p_list) {
size += s.size();
}
std::string output;
output.reserve(size);
for (auto const & s : p_list) {
output.append(s);
}
return output;
}

Answer

No, you don't need std::move. The function of std::move is to cast any value to an rvalue. Your function already returns an rvalue, thus the cast has no effect as far as binding the result to a reference is concerned (which is what you're after in order to initialize member from an rvalue).

In fact, using std::move actively inhibits copy elision, so it is a strict pessimization:

std::string s = join({});             // construct from prvalue, elidable,
                                      // elision mandatory in C++17

std::string s = std::move(join({}));  // temporary object must be constructed,
                                      // s is initialized by moving from the
                                      // temporary

In the first form, std::string s = join({});, copy elision means that the returned object of join is constructed directly in place of s (no temporary objects is constructed and copy or move is made), and moreover, the output variable in the function body is also elided and constructed directly in the return value, i.e. in s. With std::move, the first elision step is not available.

Comments