I'm trying to understand the exact behavior of object initialization in C++ when using a function that returns a reference to *this. Consider the following generic code:
class T {
public:
T& func() { /* do something */ return *this; }
};
const T obj = T().func();
And a concrete example using std::string:
const std::string fullName = std::string(firstName).append(" ").append(lastName);
Does the fact that the methods return a reference to a temporary object affect whether the copy or move constructor is used?
My understanding is that the copy constructor is called because the functions return an lvalue reference and the compiler can not know that it is from a temporary object.
However, I'm curious about potential optimizations and whether there are any nuances I'm missing.
I currently use
const T obj = std::move(T().func());
and in case of std::string I would use
const std::string fullName = std::string(firstName) + " " + std::string(lastName);
const T obj = T().func();obj will be a copy of T (copy of a reference to a const instance). It is not the same as whatstd::string::append()does. The will update internal data of the string class and then returns a reference to the same object (that now has updated content)+like you do now, will construct and destruct unecessary std::string instances. e.g.const std::string fullName{std::move(std::format("{} {}", firstName, lastName))};funcs with different ref-qualifiers. Oneconst T& func() const&and oneT&& func() &&(in which you thenreturn std::move(*this);). That way you won't needstd::move(T().func()). It'll select the correct overload automatically if you just doconst T obj = T().func();.moveis only useful for types that have managed resources. IfThas no managed resources, then a move is the same as a copy.