In Item 25 of More Effective C++, Meyer compares this code:
class Widget {
public:
template<typename T>
void setName(T&& newName) // newName is
{ name = std::forward<T>(newName); } // universal reference
…
};
To this code:
class Widget {
public:
void setName(const std::string& newName) // set from
{ name = newName; } // const lvalue
void setName(std::string&& newName) // set from
{ name = std::move(newName); } // rvalue
…
};
One drawback he outlines with the second snippet vs the first is performance:
With the version of
setNametaking a universal reference, the string literal"Adela Novak"would be passed tosetName, where it would be conveyed to the assignment operator for thestd::stringinsidew.w’s name data member would thus be assigned directly from the string literal; no temporarystd::stringobjects would arise. With the overloaded versions ofsetName, however, a temporarystd::stringobject would be created forsetName’s parameter to bind to, and this temporarystd::stringwould then be moved intow’s data member. A call tosetNamewould thus entail execution of onestd::stringconstructor (to create the temporary), onestd::stringmove assignment operator (to movenewNameintow.name), and onestd::stringdestructor (to destroy the temporary). That’s almost certainly a more expensive execution sequence than invoking only thestd::stringassignment operator taking aconst char*pointer.
But why can't you just make templates out of them, so the cast to std::string is unnecessary? As in this code, which seems to compile and run just fine with suitable adjustments:
class Widget {
public:
template<typename T>
void setName(const T& newName) // set from
{ name = newName; } // const lvalue
template<typename T>
void setName(T&& newName) // set from
{ name = std::move(newName); } // rvalue
…
};
NB: It's not that I'm arguing for this overloading strategy. Meyer's other arguments are compelling. I would just like some help understanding this particular argument about performance.