Possible Duplicate:
Should I return const objects?
(The original title of that question was: int foo() or const int foo()? explaining why I missed it.)
Effective C++, Item 3: Use const whenever possible. In particular, returning const objects is promoted to avoid unintended assignment like if (a*b = c) {
. I find it a little paranoid, nevertheless I have been following this advice.
It seems to me that returning const objects can degrade performance in C++11.
#include <iostream>
using namespace std;
class C {
public:
C() : v(nullptr) { }
C& operator=(const C& other) {
cout << "copy" << endl;
// copy contents of v[]
return *this;
}
C& operator=(C&& other) {
cout << "move" << endl;
v = other.v, other.v = nullptr;
return *this;
}
private:
int* v;
};
const C const_is_returned() { return C(); }
C nonconst_is_returned() { return C(); }
int main(int argc, char* argv[]) {
C c;
c = const_is_returned();
c = nonconst_is_returned();
return 0;
}
This prints:
copy
move
Do I implement the move assignment correctly? Or I simply shouldn't return const objects anymore in C++11?
Returning a
const
object by value arguably was never a very good idea, even before C++11. The only effect it has is that it prevents the caller from calling non-const functions on the returned object – but that is not very relevant given that the caller received a copy of the object anyway.While it is true that being returned a constant object prevents the caller from using it wrongly (e.g. mistakenly making an assignment instead of a comparison), it shouldn't be the responsibility of a function to decide how the caller can use the object returned (unless the returned object is a reference or pointer to structures the function owns). The function implementer cannot possibly know whether the object returned will be used in a comparison or for something else.
You are also right that in C++11 the problem is even graver, as returning a
const
effectively prevents move operations. (It does not prevent copy/move elision, though.)Of course it is equally important to point out that
const
is still extremely useful (and using it no sign of paranoia) when the function returns a reference or a pointer.The reason that your call to
const_is_returned
triggerscopy constructor
rather thanmove constructor
is the fact thatmove
must modify the object thus it can't be used onconst
objects. I tend to say that usingconst
isn't advised in any case and should be subjected to a programmer judgement, otherwise you get the things you demonstrated. Good question.Returning const objects is a workaround that might cause other problems. Since C++11, there is a better solution for the assignment issue: Reference Qualifiers for member functions. I try to explain it with some code:
The assignment in the second line results in a compile-time error for the builtin type
int
in both C and C++. Same for other builtin types. That's because the assignment operator for builtin types requires a non-const lvalue-reference on the left hand side. To put it in code, the assignment operator might look as follows (invalid code):It was always possible in C++ to restrict parameters to lvalue references. However, that wasn't possible until C++11 for the implicit first parameter of member functions (
*this
).That changed with C++11: Similar to const qualifiers for member functions, there are now reference qualifiers for member functions. The following code shows the usage on the copy and move operators (note the
&
after the parameter list):With this class declaration, the assignment expression in the following code fragment is invalid, whereas assigning to a local variable works - as it was in the first example.
So there is no need to return const objects. You can restrict the assigment operators to lvalue references, so that everything else still works as expected - in particular move operations.
See also: