Why will return-by-value be const for non-built types, but not const for built-in types?

Decisions 4 and 5 on GotW # 6 Const-Correctness mention this:

Point GetPoint( const int i ) { return points_[i]; } 

The return value should usually be const for non-built return types.


 int GetNumPoints() { return points_.size(); } 

.. , since int is already an rvalue and putting it in 'const' can interfere with template creation and is misleading, misleading and possibly fattening .

I have the following questions:

  • What instance of the template are we interfering here ?!
  • What exactly is misleading here and why?
  • Why is this differentiation between built-in and built-in. I thought this was bad practice!
+4
source share
2 answers
 Return-by-value should normally be const for non-builtin return types .. 

This is incorrect - one of the relatively few bugs in GotW. const rvalues โ€‹โ€‹were doubtful in C ++ 03 and certainly very bad in C ++ 11.

The problem is that in C ++ 03, r values โ€‹โ€‹can have any member function called on them, not even const. This is great because you can swap or execute method chains and other things that are great and make perfect sense, but it's also bad because the compiler can't catch you when you do something stupid, like assigning him or something, It is usually a bad idea to restrict everyone from doing good things, because the caller can do something stupid. The intention is good, but it is not.

In C ++ 11, this is fixed because you can prevent member functions from calling on rvalues, and secondly, because for the semantics of movement to work correctly, the value of r must be mutable. You cannot take resources from rvalue if it is const .

As a note, the reason is that it differs from the fact that primitive types always had a special wording built into the language, which was, for example, assigning rvalues โ€‹โ€‹to illegal, so there was no need to try to ensure its implementation by making it const .

As for the template instances, I'm not really sure. This practice, as was already known, was bad by the time I started coding with C ++, so this is not what I had to deal with.

+4
source

Personally, I do not agree with the recommendation to put const on a return value that does not depend on the semantics of the move: the value is already an rvalue value, and as a result there is no great danger of accidentally changing it. This is part of why putting const on non-line types: they may contain some kind of backdoor for the value. For example, std::vector<T> has a swap() method that can be used to "steal" the contents of the non-constant value of r:

 std::vector<int> f(); std::vector<int> value; f().swap(value); 

Similarly, streams have some member statements that allow them to be used with certain built-in functions that efficiently extract a link from a stream, for example:

 std::string word; std::istringstream("hello, world") >> std::skipws >> word; 

Without std::skipws stream is an rvalue that cannot be bound to the first argument of std::operator>> (std::istream&, std::string&) , but using a member operator for manipulators returns a non-constant reference to the stream.

const for built-in types has virtually no effect. In particular, when passing the result of a function to a function template (in C ++ 2003), it cannot distinguish between the transmitted const or non- const return. As a result, it may look like const affects inline returns, although in fact it is not.

As I said, I do not agree with this rule, and in C ++ 2011 it definitely does not work, because you want to be able to leave the non-built-in module altogether, which would be prevented by returning const .

+3
source

Source: https://habr.com/ru/post/1402140/


All Articles