Should I return const objects?

In Effective C++ Paragraph 03: Use a constant whenever possible.

 class Bigint { int _data[MAXLEN]; //... public: int& operator[](const int index) { return _data[index]; } const int operator[](const int index) const { return _data[index]; } //... }; 

const int operator[] really different from int& operator[] .

But what about:

 int foo() { } 

and

 const int foo() { } 

They seem to be the same.

My question is: why do we use const int operator[](const int index) const instead of int operator[](const int index) const ?

+69
c ++
Aug 21 2018-12-12T00:
source share
12 answers

Top-level Cv qualifiers for nonclass return type types are ignored. This means that even if you write:

 int const foo(); 

The return type is int . If the return type is a link, of course, const no longer the top level, but the difference between:

 int& operator[]( int index ); 

and

 int const& operator[]( int index ) const; 

is significant. (Note that in function declarations, as above, any higher levels of cv qualifiers are also ignored.)

The difference also matters for the return values ​​of the class type: if you return T const , then the caller cannot call non-constant functions on the return value, for example:

 class Test { public: void f(); void g() const; }; Test ff(); Test const gg(); ff().f(); // legal ff().g(); // legal gg().f(); // **illegal** gg().g(); // legal 
+79
Aug 21 '12 at 8:50
source share

You must clearly distinguish between the use of constants applied to return values, parameters, and the function itself.

Return values

  • If the function returns a value, the value of const does not matter, since a copy of the object is returned. However, this will make a difference in C ++ 11 with the involved semantics of move.
  • It also does not matter for the base types, as they are always copied.

Consider const std::string SomeMethod() const . It will not allow the use of the function (std::string&&) , since it expects a non-constant rvalue value. In other words, the returned string will always be copied.

  • If the function returns by reference, const protects the returned object from changing.

Options

  • If you pass a parameter by value, const prevents the set value from being changed by function in the function. The initial data from the parameter cannot be changed in any case, since you only have a copy.
  • Note that since a copy is always created, the constant is only relevant for the function body, therefore it is checked only in the function definition, and not in the declaration (interface).
  • If you pass the parameter by reference, the same rule applies as in the return values.

Function itself

  • If a function has const at the end, it can only run other const functions and cannot modify or allow modification of class data. Thus, if it is returned by reference, the returned link must be const. Only an const function can be called on an object or a reference to an object that is a constant itself. Also changeable fields can be changed.
  • The behavior created by the compiler modifies this reference to T const* . A function can always const_cast this , but, of course, it should not be executed and is considered unsafe.
  • Of course, it makes sense to use this specifier only for class methods; global functions with a constant at the end will cause a compilation error.

Conclusion

If your method does not and does not change the class variables, mark it as const and be sure to fulfill all the necessary criteria. This will allow you to write cleaner code, while maintaining its constant. However, putting const everywhere, without giving him any thought, of course, this is not the way to go.

+31
Aug 21 '12 at 8:50
source share

In adding const to values ​​without reference / not pointer and there is no point when adding it to the built-in.

In the case of user-defined types, the const qualification will prevent callers from calling a non- const member function for the returned object. For example, given

 const std::string foo(); std::string bar(); 

then

 foo().resize(42); 

would be forbidden as well

 bar().resize(4711); 

will be allowed.

For built-in functions such as int , this makes no sense, because such values ​​cannot be changed in any way.

(I remember that effective C ++ discusses the issue of returning type operator=() a const , and this needs to be considered.)




Edit:

It seems that Scott really gave this advice . If this is the case, then due to the reasons given above, I find it doubtful even for C ++ 98 and C ++ 03 . For C ++ 11, I find this incorrectly wrong , as Scott himself seems to have discovered. In errata for Effective C ++, 3rd ed. he writes (or quotes others who complained):

The text implies that all returned values ​​must be const, but cases where non-constant useful values ​​are a good construction are not difficult to find, for example, returning std :: vector types when callers use a swap with an empty vector so that " capture the contents of the return value without copying them.

And later:

Declaring the return values ​​of the const function will prevent them from being bound to rvalue values ​​in C ++ 0x. Since rvalue links are designed to help increase the efficiency of C ++ code, it is important to consider the interaction of const constant values ​​and the initialization of rvalue links when specifying function signatures.

+26
Aug 21 2018-12-12T00: 00Z
source share

You may miss a point on Meyers advice. The significant difference lies in the const modifier for the method.

This method is non-constant (note the const at the end), which means that it is allowed to change the state of the class.

 int& operator[](const int index) 

This method is constant ( const notice at the end)

 const int operator[](const int index) const 

As for the types of the parameter and the return value, there is a slight difference between int and const int , but this does not apply to the point of recommendation. What you should pay attention to is that non-constant overload returns int& , which means that you can assign it to it, for example. num[i]=0 , and const overload returns a non-modifiable value (regardless of the return type int or const int ).

In my personal opinion, if an object is passed by value , the const modifier is superfluous. This syntax is shorter and achieves the same

 int& operator[](int index); int operator[](int index) const; 
+17
Aug 21 '12 at 8:40
source share

The main reason for returning values ​​as const is that you cannot say something like foo() = 5; . This is actually not a problem with primitive types, since you cannot assign rvalues ​​to primitive types, but it is a problem with custom types (e.g. (a + b) = c; ;, with operator+ overloaded).

I have always considered the excuse for this rather flimsy. You cannot stop someone who intends to write inconvenient code, and this particular type of coercion is not of real use, in my opinion.

With C ++ 11, this idiom is actually very harmful: the returned values ​​of as const prevent motion optimization and should therefore be avoided when possible. Basically, now I consider this an anti-pattern.

Here's a tangentially related article on C ++ 11.

+13
Aug 21 2018-12-12T00:
source share

When this book was written, the advice was of little use, but served to prevent the user from writing, for example, foo() = 42; , and expected him to change something permanent.

In the case of operator[] this can be a bit confusing if you also do not provide a non- const overload that returns a non- const link, although you can possibly prevent this confusion by returning a const link or proxy object instead of a value.

This is bad advice these days, as it prevents you from binding the result to the (n const ) rvalue reference.

(As indicated in the comments, the question arises when returning a primitive type of type int , since the language does not allow you to assign an rvalue this type, I'm talking about a more general one that involves returning user types.)

+9
Aug 21 '12 at 8:40
source share

For primitive types (e.g. int ), the constant of the result does not matter. For classes, this can change behavior. For example, you cannot call the non-const method for the result of your function:

 class Bigint { const C foo() const { ... } ... } Bigint b; b.foo().bar(); 

The above is prohibited if bar() is a const member function of C In general, choose what makes sense.

+2
Aug 21 2018-12-12T00:
source share

Look at this:

 const int operator[](const int index) const 

the const at the end of the statement. He describes that this method can be called by constants.

On the other hand, when you write only

 int& operator[](const int index) 

it can only be called for non-const instances, and also provide:

 big_int[0] = 10; 

syntax.

0
Aug 21 2018-12-12T00:
source share

One of your overloads returns a link to an array element that you can then modify.

 int& operator[](const int index) { return _data[index]; } 

Another overload returns the value to use.

 const int operator[](const int index) const { return _data[index]; } 

Since you call each of these overloads in the same way, and you will never change the value when it will be used.

 int foo = myBigInt[1]; // Doesn't change values inside the object. myBigInt[1] = 2; // Assigns a new value at index ` 
0
Aug 21 2018-12-12T00:
source share

In the example array indexing operator[] ( operator[] ), this matters.

FROM

 int& operator[](const int index) { /* ... */ } 

you can use indexing to directly modify an entry in an array, for example. using it as follows:

 mybigint[3] = 5; 

The second, const int operator[](const int) used only to get the value.

However, as a return value from functions, for simple types, for example, for example. int It does not matter. When that matters, you return more complex types, say std::vector , and you do not want the caller to modify the vector.

0
Aug 21 2018-12-12T00:
source share

The return type const is not so important here. Since temporary variables do not change, there is no difference in using int vs const int . You would notice the difference if you used a more complex object that could be modified.

0
Aug 21 2018-12-12T00:
source share

There are some good answers related to the technique of the two versions. For a primitive value, this does not matter.

However , I always considered const for the programmer, not for the compiler. When you write const , you explicitly say "this should not change." Turn face to face, const can even be circled, right?

When you return const , you tell the programmer who uses this function, the value should not change. And if he changes it, he probably does something wrong, because he / she does not need.

EDIT: I also think that “use const whenever possible”, these are bad tips. You should use it where it makes sense.

0
Aug 21 '12 at 9:01
source share



All Articles