Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I still return const objects in C++11? [duplicate]

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?

like image 660
Ali Avatar asked Oct 27 '12 11:10

Ali


People also ask

What is a situation in which returning a const value is good idea?

In the hypothetical situation where you could perform a potentially expensive non-const operation on an object, returning by const-value prevents you from accidentally calling this operation on a temporary.

When should I return my const?

Thus, it's important to use const when returning an object by value if you want to prevent its use as an lvalue. The reason const has no meaning when you're returning a built-in type by value is that the compiler already prevents it from being an lvalue (because it's always a value, and not a variable).

Can const be redefined?

Constants are block-scoped, much like variables declared using the let keyword. The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be redeclared (i.e. through a variable declaration).

Can we change the value of const variable in C?

In C or C++, we can use the constant variables. The constant variable values cannot be changed after its initialization.


3 Answers

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:

int foo(); // function declaration foo() = 42; // ERROR 

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):

int& operator=(int& lhs, const int& rhs); 

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):

struct Int {     Int(const Int& rhs) = default;     Int(Int&& rhs) noexcept = default;     ~Int() noexcept = default;     auto operator=(const Int& rhs) & -> Int& = default;     auto operator=(Int&& rhs) & noexcept -> Int& = default; }; 

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.

Int bar(); Int baz(); bar() = baz(); // ERROR: no viable overloaded '=' 

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:

  • What is "rvalue reference for *this"?
like image 70
nosid Avatar answered Sep 21 '22 14:09

nosid


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.

like image 24
jogojapan Avatar answered Sep 19 '22 14:09

jogojapan


The reason that your call to const_is_returned triggers copy constructor rather than move constructor is the fact that move must modify the object thus it can't be used on const objects. I tend to say that using const isn't advised in any case and should be subjected to a programmer judgement, otherwise you get the things you demonstrated. Good question.

like image 28
SomeWittyUsername Avatar answered Sep 18 '22 14:09

SomeWittyUsername