Three functions return a vector by value at -O2: one returns a local variable, one returns a data member of the object, one returns std::move of a local. For each, say whether a copy or a move constructor runs and whether an allocation happens, then rank the three by cost.
Three functions return a vector by value at -O2: one returns a local variable, one returns a data member of the object, one returns std::move of a local. For each, say whether a copy or a move constructor runs and whether an allocation happens, then rank the three by cost.
Approach: Apply the elision rules to a returned local name, then the overload resolution rules to a returned member expression, then ask what naming the result as an xvalue does to elision.
The local is elided with no constructor call and no allocation, std::move of a local runs one move construction with no allocation, and the member runs a copy construction with one allocation, so the ranking from cheapest is local, moved local, member. Returning a local by name lets the compiler construct the object directly in the caller storage, which is named return value optimisation, so zero constructors run. Writing return std::move of a local makes the return expression an xvalue rather than the name of a local, which disqualifies the elision and leaves a move constructor call, cheap for a vector and still more than nothing. A returned data member is an lvalue that outlives the call and the function does not own it, so the compiler must copy, which is one allocation plus an element wise copy.
Follow-up: What changes if the accessor returning the member is given an rvalue-qualified overload?
Key concepts: copy elision, named return value optimisation, xvalue, move construction.