Should I make my local variables const or movable? - c++

My default behaviour for any objects in local scopes is to make it const. E.g.:
auto const cake = bake_cake(arguments);
I try to have as little non-functional code as I can as this increases readability (and offers some optimisation opportunities for the compiler). So it is logical to also reflect this in the type system.
However, with move semantics, this creates the problem: what if my cake is hard or impossible to copy and I want to pass it out after I'm done with it? E.g.:
if (tastes_fine(cake)) {
return serve_dish(cake);
}
As I understand copy elision rules it's not guaranteed that the cake copy will be elided (but I'm not sure on this).
So, I'd have to move cake out:
return serve_dish(std::move(cake)); // this will not work as intended
But that std::move will do nothing useful, as it (correctly) will not cast Cake const& to Cake&&. Even though the lifetime of the object is very near its end. We cannot steal resources from something we promised not to change. But this will weaken const-correctness.
So, how can I have my cake and eat it too?
(i.e. how can I have const-correctness and also benefit from move semantics.)

I believe it's not possible to move from a const object, at least with a standard move constructor and non-mutable members. However, it is possible to have a const automatic local object and apply copy elision (namely NRVO) for it. In your case, you can rewrite your original function as follows:
Cake helper(arguments)
{
const auto cake = bake_cake(arguments);
... // original code with const cake
return cake; // NRVO
}
Then, in your original function, you can just call:
return serve_dish(helper(arguments));
Since the object returned by helper is already a non-const rvalue, it may be moved-from (which may be, again, elided, if applicable).
Here is a live-demo that demonstrates this approach. Note that there are no copy/move constructors called in the generated assembly.

You should indeed continue to make your variables const as that is good practice (called const-correctness) and it also helps when reasoning about code - even while creating it. A const object cannot be moved from - this is a good thing - if you move from an object you are almost always modifying it to a large degree or at least that is implied (since basically a move implies stealing the resources owned by the original object) !
From the core guidelines:
You can’t have a race condition on a constant. It is easier to reason
about a program when many of the objects cannot change their values.
Interfaces that promises “no change” of objects passed as arguments
greatly increase readability.
and in particular this guideline :
Con.4: Use const to define objects with values that do not change
after construction
Moving on to the next, main part of the question:
Is there a solution that does not exploit NRVO?
If by NRVO you take to include guaranteed copy elision, then not really, or yes and no at the same. This is somewhat complicated. Trying to move the return value out of a return by value function doesn't necessarily do what you think or want it to. Also, a "no copy" is always better than a move performance-wise. Therefore, instead you should try to let the compiler do it's magic and rely in particular on guaranteed copy elision (since you use c++17). If you have what I would call a complex scenario where elision is not possible: you can then use a move combined with guaranteed copy elision/NRVO, so as to avoid a full copy.
So the answer to that question is something like: if you object is already declared as const, then you can almost always rely on copy-elision/return by value directly, so use that. Otherwise you have some other scenario and then use discretion as to the best approach - in rare cases a move could be in order(meaning it's combined with copy-elision).
Example of 'complex' scenario:
std::string f() {
std::string res("res");
return res.insert(0, "more: ");//'complex scenario': a reference gets returned here will usually mean a copy is invoked here.
}
Superior way to 'fix' is to use copy-elision i.e.:
return res;//just return res as we already had that thus avoiding copy altogether - it's possible that we can't use this solution for more *hairy/complex* scenarios.
Inferior way to 'fix' in this example would be;
return std::move(res.insert(0, "more: "));

Make them movable if you can.
It's time to change your "default behaviour" as it's anachronistic.
If move semantics were built into the language from inception then making automatic variables const would have quickly become established as poor programming practice.
const was never intended to be used for micro-optimisations. Micro-optimisations are best left to the compiler. const exists primarily for member variables and member functions. It's also helped clean up the language a little: e.g. "foo" is a const char[4] type whereas in C it's a char[4] type with the curious understanding that you're not allowed to modify the contents.
Now (since C++11) const for automatic variables can actually be harmful as you observe, the time has come to stop this practice. The same can be said for const parameter by-value types. Your code would be less verbose too.
Personally I prefer immutable objects to const objects.

It seems to me, that if you want to move, than it will be "const correct" to not declare it const, because you will(!) change it.
It's ideological contradiction. You cannot move something and leave in place at the same time.
You mean, that object will be const for a part of time, in some scope. In this case, you can declare const reference to it, but it seems to me, that this will complicate the code and will add no safety.
Even vice versa, if you accidentally use the const reference to object after std::move() there will be problems, despite it will look like work with const object.

A limited workaround would be const move constructor:
class Cake
{
public:
Cake(/**/) : resource(acquire_resource()) {}
~Cake() { if (owning) release_resource(resource); }
Cake(const Cake& rhs) : resource(rhs.owning ? copy_resource(rhs.resource) : nullptr) {}
// Cake(Cake&& rhs) // not needed, but same as const version should be ok.
Cake(const Cake&& rhs) : resource(rhs.resource) { rhs.owning = false; }
Cake& operator=(const Cake& rhs) {
if (this == &rhs) return *this;
if (owning) release_resource(resource);
resource = rhs.owning ? copy_resource(rhs.resource) : nullptr;
owning = rhs.owning;
}
// Cake& operator=(Cake&& rhs) // not needed, but same as const version should be ok.
Cake& operator=(const Cake&& rhs) {
if (this == &rhs) return *this;
if (owning) release_resource(resource);
resource = rhs.resource;
owning = rhs.owning;
rhs.owning = false;
}
// ...
private:
Resource* resource = nullptr;
// ...
mutable bool owning = true;
};
Require extra mutable member.
not compatible with std containers which will do copy instead of move (providing non const version will leverage copy in non const usage)
usage after move should be considered (we should be in valid state, normally). Either provide owning getter, or "protect" appropriate methods with owning check.
I would personally just drop the const when move is used.

Related

Why not to copy a class consisting of a single shared_ptr

Recently, I read an article about lazy data structures in C++ (this question is not about lazy, or the particular data structure, though - it is just the motivation).
A lazy stream (list) is implemented as follows:
template<class T>
class Stream
{
private:
std::shared_ptr <Susp<Cell<T>>> _lazyCell;
public:
Stream() {}
Stream(std::function<Cell<T>()> f)
: _lazyCell(std::make_shared<Susp<Cell<T>>>(f))
{}
Stream(Stream && stm)
: _lazyCell(std::move(stm._lazyCell))
{}
Stream & operator=(Stream && stm)
{
_lazyCell = std::move(stm._lazyCell);
return *this;
}
bool isEmpty() const
{
return !_lazyCell;
}
T get() const
{
return _lazyCell->get().val();
}
Stream<T> pop_front() const
{
return _lazyCell->get().pop_front();
}
};
The author mentions the move constructor:
I also added a move constructor and a move assignment operator for efficiency.
However, due to the explicit presence, one cannot simply assign a Stream. What is the motivation behind this?
As far as I can tell, the class consists solely of a shared_ptr, which can be trivially copied. Is there any benefit in forbidding copy-construction in such a class?
The shared_ptr is used internally to share lazy value cells as part of the private implementation.
However, from the user's point of view, it's an immutable object. Providing a copy constructor and assignment operator would undo this immutability.
He is modelling Haskell's immutable object's behaviour.
If it were thread-safe to do so, it would be reasonable to make this object copyable since in reality it's a handle to an (albeit more complex than usual) shared impl.
However, copyers would need to understand that they were copying a handle to shared state, and not state itself.
I think this is a type of premature optimization.
First of all, due to the rule of three/five (http://en.cppreference.com/w/cpp/language/rule_of_three), the move copy/assignment constructors would have been created in the same way without typing it out.
Therefore the only difference is, as you already pointed out, the missing copy/assigment constructor. It would have been better practice to mark them as deleted, e.g.:
Stream(Stream & stm) = deleted;
However the real problem here is using a shared pointer with only a single owner. It would have been much better to just use a std::unique_ptr. With its use copy and assignment are disabled automatically and the intent of the author is much clearer.

Why does moving a pointer variable not set it to null?

When implementing move constructors and move assignment operators, one often writes code like this:
p = other.p;
other.p = 0;
The implicitly defined move operations would be implemented with code like this:
p = std::move(other.p);
Which would be wrong, because moving a pointer variable does not set it to null. Why is that? Are there any cases were we would like the move operations to leave the original pointer variable unchanged?
Note: By "moving", I do not just mean the subexpression std::move(other.p), I mean the whole expression p = std::move(other.p). So, why is there no special language rule that says "If the right hand side of an assignment is a pointer xvalue, it is set to null after the assignment has taken place."?
Setting a raw pointer to null after moving it implies that the pointer represents ownership. However, lots of pointers are used to represent relationships. Moreover, for a long time it is recommended that ownership relations are represented differently than using a raw pointer. For example, the ownership relation you are referring to is represented by std::unique_ptr<T>. If you want the implicitly generated move operations take care of your ownership all you need to do is to use members which actually represent (and implement) the desired ownership behavior.
Also, the behavior of the generated move operations is consistent with what was done with the copy operations: they also don't make any ownership assumptions and don't do e.g. a deep copy if a pointer is copied. If you want this to happen you also need to create a suitable class encoding the relevant semantics.
Moving renders the moved-from object "invalid". It does not automatically set it to a safe "empty" state. In accordance with C++'s long-standing principle of "don't pay for what you don't use", that's your job if you want it.
I think the answer is : implementing such a behavior yourself is pretty much trivial and hence the Standard didn't feel any need to impose any rule on the compiler itself. The C++ language is huge and not everything can be imagined before its use. Take for example, C++'s template. It was not first designed to be used the way it is used today (i.e it's metaprogramming capability). So I think, the Standard just gives the freedom, and didn't make any specific rule for std::move(other.p), following one of it's the design-principle: "You don't pay for what you don't use".
Although, std::unique_ptr is movable, though not copyable. So if you want pointer-semantic which is movable and copyable both, then here is one trivial implementation:
template<typename T>
struct movable_ptr
{
T *pointer;
movable_ptr(T *ptr=0) : pointer(ptr) {}
movable_ptr<T>& operator=(T *ptr) { pointer = ptr; return *this; }
movable_ptr(movable_ptr<T> && other)
{
pointer = other.pointer;
other.pointer = 0;
}
movable_ptr<T>& operator=(movable_ptr<T> && other)
{
pointer = other.pointer;
other.pointer = 0;
return *this;
}
T* operator->() const { return pointer; }
T& operator*() const { return *pointer; }
movable_ptr(movable_ptr<T> const & other) = default;
movable_ptr<T> & operator=(movable_ptr<T> const & other) = default;
};
Now you can write classes, without writing your own move-semantics:
struct T
{
movable_ptr<A> aptr;
movable_ptr<B> bptr;
//...
//and now you could simply say
T(T&&) = default;
T& operator=(T&&) = default;
};
Note that you still have to write copy-semantics and the destructor, as movable_ptr is not smart pointer.
For example, if you have a pointer to a shared object. Remember, that after moving an object must remain in an internally consistent state, so setting a pointer that must not be null to a null value is not correct.
I.e.:
struct foo
{
bar* shared_factory; // This can be the same for several 'foo's
// and must never null.
};
Edit
Here is a quote about MoveConstructibe from the standard:
T u = rv;
...
rv’s state is unspecified [ Note:rv must still meet the requirements
of the library component that is using it. The operations listed in
those requirements must work as specified whether rv has been moved
from or not.
I think what makes the difference here is a fully blown object on the one hand and a POD on the other hand.
For objects either the implementer specifies what move construction and move assignment should do or the compiler generates a default. The default is to call the move constructors/assignment operators of all member.
For POD's (and a pointer is a POD) C++ inherits from C and nothing is done with it when not explicitely coded. It's just the same behavior as POD members in a class are treated in a constructor. If you don't explicitely put them in the initializer list, well, then they stay uninitialized and are a source of potential bugs. AFAIK this is even valid for compiler generated constructors! That's why I took on the habit of generally initializing all members to be on the safe side.

Move semantics - what it's all about? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Can someone please explain move semantics to me?
Could someone point me to a good source or explain it here what are the move semantics?
Forget about C++0x for the moment. Move semantics are something that is language independent -- C++0x merely provides a standard way to perform operations with move semantics.
Definition
Move semantics define the behaviour of certain operations. Most of the time they are contrasted with copy semantics, so it would be useful to define them first.
Assignment with copy semantics has the following behaviour:
// Copy semantics
assert(b == c);
a = b;
assert(a == b && b == c);
i.e. a ends up equal to b, and we leave b unchanged.
Assignment with move semantics has weaker post conditions:
// Move semantics
assert(b == c);
move(a, b); // not C++0x
assert(a == c);
Note that there is no longer any guarantee that b remains unchanged after the assignment with move semantics. This is the crucial difference.
Uses
One benefit of move semantics is that it allows optimisations in certain situations. Consider the following regular value type:
struct A { T* x; };
Assume also that we define two objects of type A to be equal iff their x member point to equal values.
bool operator==(const A& lhs, const A& rhs) { return *lhs.x == *rhs.x; }
Finally assume that we define an object A to have sole ownership over the pointee of their x member.
A::~A() { delete x; }
A::A(const A& rhs) : x(new T(rhs.x)) {}
A& A::operator=(const A& rhs) { if (this != &rhs) *x = *rhs.x; }
Now suppose we want to define a function to swap two A objects.
We could do it the normal way with copy semantics.
void swap(A& a, A& b)
{
A t = a;
a = b;
b = t;
}
However, this is unnecessarily inefficient. What are we doing?
We create a copy of a into t.
We then copy b into a.
Then copy t into b.
Finally, destroy t.
If T objects are expensive to copy then this is wasteful. If I asked you to swap two files on your computer, you wouldn't create a third file then copy and paste the file contents around before destroying your temporary file, would you? No, you'd move one file away, move the second into the first position, then finally move the first file back into the second. No need to copy data.
In our case, it's easy to move around objects of type A:
// Not C++0x
void move(A& lhs, A& rhs)
{
lhs.x = rhs.x;
rhs.x = nullptr;
}
We simply move rhs's pointer into lhs and then relinquish rhs ownership of that pointer (by setting it to null). This should illuminate why the weaker post condition of move semantics allows optimisations.
With this new move operation defined, we can define an optimised swap:
void swap(A& a, A& b)
{
A t;
move(t, a);
move(a, b);
move(b, t);
}
Another advantage of move semantics is that it allows you to move around objects that are unable to be copied. A prime example of this is std::auto_ptr.
C++0x
C++0x allows move semantics through its rvalue reference feature. Specifically, operations of the kind:
a = b;
Have move semantics when b is an rvalue reference (spelt T&&), otherwise they have copy semantics. You can force move semantics by using the std::move function (different from the move I defined earlier) when b is not an rvalue reference:
a = std::move(b);
std::move is a simple function that essentially casts its argument to an rvalue reference. Note that the results of expressions (such as a function call) are automatically rvalue references, so you can exploit move semantics in those cases without changing your code.
To define move optimisations, you need to define a move constructor and move assignment operator:
T::T(T&&);
T& operator=(T&&);
As these operations have move semantics, you are free to modify the arguments passed in (provided you leave the object in a destructible state).
Conclusion
That's essentially all there is to it. Note that rvalue references are also used to allow perfect forwarding in C++0x (due to the specifically crafted type system interactions between rvalue references and other types), but this isn't really related to move semantics, so I haven't discussed it here.
Basically, rvalue references allow you to detect when objects are temporaries and you don't have to preserve their internal state. This allows for much more efficient code where C++03 used to have to copy all the time, in C++0x you can keep re-using the same resources. In addition, rvalue references enable perfect forwarding.
Have a look at this answer.
I read a ton of text explanations for about a year and didn't grasp everything about r-value references until I watch this excellent presentation by Scott Meyer : http://skillsmatter.com/podcast/home/move-semanticsperfect-forwarding-and-rvalue-references
He explain in a way that is funny and slow enough to understand each thing that happens in the processes.
I know, it 1h30 but really, it's the best explanation I've had in the last year.
After having read the articles (like the other answers), watching this video did melt it together in my mind in a consistent way and few days after I was able to explain it to some colleagues and explain how to use std::unique_ptr (as it is related - it only allow move semantics, not copy) because it requires understanding of std::move(), that requires understanding move semantics.
glad to see such a question and I'm happy to share my point. I think you are asking about a bug-fix on the designation of the C++ language itself, not just another C++ language feature. The "bug" has been there for tens of year. That is, the copy constructor.
Copy constructors seems very strange if you know in physics there are lots of things that can not be copied like energy and mass. That's just a joke, but in fact in the world of programming too, objects like exclusive file descriptors are not copyable. So C++ programmers and designers invented some tricks to deal with that. There are 3 famous: NRVO, boost::noncopyable and std::auto_ptr.
NRVO (Named Return Value Optimization) is a technic that lets a function returns an object by value without calling the copy constructor. But the problem with NRVO is that though the copy constructor is not actually called, a public copy constructor declaration is still needed, which means, objects of boost::noncopyable is not compatible with NRVO.
std::auto_ptr is another trial to bypass the copy constructor. You might have seen its "copy constructor" implemented like
template <typename _T>
auto_ptr(auto_ptr<_T>& source)
{
_ptr = source._ptr; // where _ptr is the pointer to the contained object
source._ptr = NULL;
}
This is not a copy at all, but a "move". You could consider this kind of behavior as the prototype of a move semantic.
But std::auto_ptr also has its own problem: it is not compatible with STL containers. So, unfortunately, anything about noncopyable is painful.
That was painful until, the C++0x move semantic is finally published and implemented by the compiler makers.
In simple way, you could just think of move semantic as something same as the "copy" behavior of std::auto_ptr, but with a full support by the language features so it works fine with containers and algorithm.
By the way in C++0x the std::auto_ptr is deprecated and a new template type std::unique_ptr is recommended.
My story will end now. Please refer to other posts if you want to know more about it like strange syntax and rvalue system.

Who deletes the copied instance in + operator ? (c++)

I searched how to implement + operator properly all over the internet and all the results i found do the following steps :
const MyClass MyClass::operator+(const MyClass &other) const
{
MyClass result = *this; // Make a copy of myself. Same as MyClass result(*this);
result += other; // Use += to add other to the copy.
return result; // All done!
}
I have few questions about this "process" :
Isn't that stupid to implement + operator this way, it calls the assignment operator(which copies the class) in the first line and then the copy constructor in the return (which also copies the class , due to the fact that the return is by value, so it destroys the first copy and creates a new one.. which is frankly not really smart ... )
When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself.
who deletes the copy that b+c created ?
Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?
thanks in advance
That's effectively not an assignment operator, but a copy constructor. An operation like addition creates a new value, after all, so it has to be created somewhere. This is more efficient than it seems, since the compiler is free to do Return Value Optimization, which means it can construct the value directly where it will next be used.
The result is declared as a local variable, and hence goes away with the function call - except if RVO (see above) is used, in which case it was never actually created in the function, but in the caller.
Not really; this method is much more efficient than it looks at first.
Under the circumstances, I'd probably consider something like:
MyClass MyClass::operator+(MyClass other) {
other += *this;
return other;
}
Dave Abrahams wrote an article a while back explaining how this works and why this kind of code is usually quite efficient even though it initially seems like it shouldn't be.
Edit (thank you MSalters): Yes, this does assume/depend upon the commutative property holding for MyClass. If a+b != b+a, then the original code is what you want (most of the same reasoning applies).
it calls the assignment operator(which copies the class) in the first line
No, this is copy-initialization (through constructor).
then the copy constructor in the return (which also copies the class
Compilers can (and typically do) elide this copy using NRVO.
When i write a=b+c, the b+c part creates a new copy of the class, then the 'a=' part copies the copy to himself. who deletes the copy that b+c created
The compiler, as any other temporary value. They are deleted at the end of full-expression (in this case, it means at or after ; at the end of line.
Is there a better way to implement + operator without coping the class twice, and also without any memory issues ?
Not really. It's not that inefficient.
This appears to be the correct way to implement operator+. A few points:
MyClass result = *this does not use the assignment operator, it should be calling the copy constructor, as if it were written MyClass result(*this).
The returned value when used in a = b + c is called a temporary, and the compiler is responsible for deleting it (which will probably happen at the end of the statement ie. the semicolon, after everything else has been done). You don't have to worry about that, the compiler will always clean up temporaries.
There's no better way, you need the copy. The compiler, however, is allowed to optimise away the temporary copies, so not as many as you think may be made. In C++0x though, you can use move constructors to improve performance by transfering ownership of the content of a temporary rather than copying it in its entirity.
I'll try my best to answer:
Point (1): No, it does not call the assignment operator. Instead it calls a constructor. Since you need to construct the object anyway (since operator+ returns a copy), this does not introduce extra operations.
Point (2): The temporary result is created in stack and hence does not introduce memory problem (it is destroyed when function exits). On return, a temporary is created so that an assignment (or copy constructor) can be used to assign the results to a (in a=b+c;) even after result is destroyed. This temporary is destroyed automatically by the compiler.
Point (3): The above is what the standard prescribes. Remember that compiler implementors are allowed to optimize the implementation as long as the effect is the same as what the standard prescribed. I believe, compilers in reality optimize away many of the copying that occurs here. Using the idiom above is readable and is not actually inefficient.
P.S. I sometime prefer to implement operator+ as a non-member to leverage implicit conversion for both sides of the operators (only if it makes sense).
There are no memory issues (provided that the assignment operator, and copy constructor are well written). Simply because all the memory for these objects is taken on the stack and managed by the compiler. Furthermore, compilers do optimize this and perform all the operations directly on the final a instead of copying twice.
This is the proper way of implementing the operator+ in C++. Most of the copies you are so afraid of will get elided by the compiler and will be subject to move semantics in C++0x.
The class is a temporary and will be deleted. If you bind the temporary to a const& the life time of the temporary will be extended to the life time of the const reference.
May implementing it as a freefunction is a little more obvious. The first parameter in MyClass::operator+ is an implicit this and the compiler will rewrite the function to operator+(const MyClass&, const MyClass&) anyway.
As far as I remember, Stroustrup's 'The C++ Programming Language' recommends to implement operators as member functions only when internal representation is affected by operation and as external functions when not. operator+ does not need to access internal representation if implemented based on operator+=, which does.
So you would have:
class MyClass
{
public:
MyClass& operator+=(const MyClass &other)
{
// Implementation
return *this;
}
};
MyClass operator+(const MyClass &op1, const MyClass &op2)
{
MyClass r = op1;
return r += op2;
}

Is it more efficient to return a const reference

E.g.
What's best out of these:
std::string f() {}
or
const std::string& f() {}
A function should never return a reference to a local object/variable since such objects go out of the scope and get destroyed when the function returns.
Differently, the function can return a const or non const reference to an object whose scope is not limited by the function context. Typical example is a custom operator<<:
std::ostream & operator<<(std::ostream &out, const object &obj)
{
out << obj.data();
return out;
}
Unfortunately, returning-by-value has its performance drawback. As Chris mentioned, returning an object by value involves the copy of a temporary object and its subsequent destruction. The copy takes place by means of either copy constructor or operator=. To avoid these inefficiencies, smart compilers may apply the RVO or the NRVO optimizations, but there are cases in which they can't -- multiple returns.
The upcoming C++0x standard, partially available in gnu gcc-4.3, introduces the rvalue reference [&&] that can be used to distinguish a lvalue from a rvalue reference. By means of that, it's possible to implement the move constructor, useful to return an object partially avoiding the cost of copy constructor and the destructor of the temporary.
The move constructor is basically what Andrei envisioned some years ago in the article http://www.ddj.com/database/184403855 suggested by Chris.
A move constructor has the following signature:
// move constructor
object(object && obj)
{}
and it's supposed to take the ownership of the internals of the passed object leaving the latter in a default state. By doing that, copies of internals are avoided and the destruction of the temporary made easy. A typical function factory will then have the following form:
object factory()
{
object obj;
return std::move(obj);
}
The std::move() returns a rvalue reference from an object. Last but not least, move constructors allow the return-by-rvalue-reference of non-copyable objects.
I would like to add to Nicola's excellent answer. Yes, you must never return a dangling reference (e.g., reference to a local variable), however, there are three useful ways to improve performance in those cases:
Return-value optimisation (RVO): You return by value, but eliminate copying by having only one return statement, which creates the return value on the spot. Here's an example of RVO being used: How can I tokenize a C++ string?
Named return-value optimisation (NRVO): You return by value, and declare the return value variable first, at the top of the function. All return statements return that variable. With compilers that support NRVO, that variable is allocated in the return-value slot, and does not get copied upon return. e.g.,
string
foobar()
{
string result;
// fill in "result"
return result;
}
Use a shared_ptr or the like as the return type; this necessitates creating your object on the heap, rather than the stack. This prevents dangling-reference problems while still not requiring the whole object to be copied, just the smart pointer.
By the way, I can't take credit for the information about RVO and NRVO; they come straight out of Scott Meyers's More Effective C++. Since I don't have the book with me at the moment, any errors in my description are my doing, not Scott's. :-)
If you return a reference to a variable that is local to the function then you're going to end up with issues (depending on the compiler and its settings).
If you return a reference to an instance that's still in scope when the function returns then it will be faster, as no copy of the string is being created.
So the latter is more efficient (technically) but may not function as expected depending on what you return a reference to.