Purpose of returning by const value? [duplicate]

2019-01-01 13:12发布

问题:

This question already has an answer here:

  • What are the use cases for having a function return by const value for non-builtin type? 3 answers

What is the purpose of the const in this?

const Object myFunc(){
    return myObject;
}

I\'ve just started reading Effective C++ and Item 3 advocates this and a Google search picks up similar suggestions but also counterexamples. I can\'t see how using const here would ever be preferable. Assuming a return by value is desirable, I don\'t see any reason to protect the returned value. The example given for why this might be helpful is preventing unintended bool casts of the return value. The actual problem then is that implicit bool casts should be prevented with the explicit keyword.

Using const here prevents using temporary objects without assignment. So I couldn\'t perform arithmetic expressions with those objects. It doesn\'t seem like there\'s ever a case that an unnamed const is useful.

What is gained by using const here and when would it be preferable?

EDIT: Change arithmetic example to any function that modifies an object that you might want to perform before an assignment.

回答1:

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. Imagine that + returned a non-const value, and you could write:

(a + b).expensive();

In the age of C++11, however, it is strongly advised to return values as non-const so that you can take full advantage of rvalue references, which only make sense on non-constant rvalues.

In summary, there is a rationale for this practice, but it is essentially obsolete.



回答2:

It\'s pretty pointless to return a const value from a function.

It\'s difficult to get it to have any effect on your code:

const int foo() {
   return 3;
}

int main() {
   int x = foo();  // copies happily
   x = 4;
}

and:

const int foo() {
   return 3;
}

int main() {
   foo() = 4;  // not valid anyway for built-in types
}

// error: lvalue required as left operand of assignment

Though you can notice if the return type is a user-defined type:

struct T {};

const T foo() {
   return T();
}

int main() {
   foo() = T();
}

// error: passing ‘const T’ as ‘this’ argument of ‘T& T::operator=(const T&)’ discards qualifiers

it\'s questionable whether this is of any benefit to anyone.

Returning a reference is different, but unless Object is some template parameter, you\'re not doing that.



回答3:

It makes sure that the returned object (which is an RValue at that point) can\'t be modified. This makes sure the user can\'t do thinks like this:

myFunc() = Object(...);

That would work nicely if myFunc returned by reference, but is almost certainly a bug when returned by value (and probably won\'t be caught by the compiler). Of course in C++11 with its rvalues this convention doesn\'t make as much sense as it did earlier, since a const object can\'t be moved from, so this can have pretty heavy effects on performance.



回答4:

C++11 makes it rather useful with move-only objects. For example:

const std::unique_ptr<T> myFunc();

unique_ptr is a type that cannot be copied; it can only be moved. But you cannot call std::move on a const type. Therefore, the only way to store this is with a const& or const&&:

const std::unique_ptr<T> &ptr = myFunc();

Since it\'s a const unique_ptr, it cannot be moved from. Nor can it be copied from. Which means that it is very difficult to actually store this anywhere long-term. You can put it on the stack. But making it a member of a class is impossible (without invoking undefined behavior).

This way, one can ensure that the pointer doesn\'t get stored long-term. This allows one to create a specialized version of unique_ptr who\'s deleter doesn\'t actually delete the memory. That way, a function can return a pointer knowing that the user cannot store it anywhere.

Of course, this also makes it rather difficult for the caller to return the value. So there are downsides.



回答5:

It could be used as a wrapper function for returning a reference to a private constant data type. For example in a linked list you have the constants tail and head, and if you want to determine if a node is a tail or head node, then you can compare it with the value returned by that function.

Though any optimizer would most likely optimize it out anyway...



回答6:

myObject could be a pointer. The \'const\' there is protecting the value pointed to by myObject.



标签: c++ const