简体   繁体   中英

Should I return const objects?

In Effective C++<\/code> Item 03, Use const 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]; }
  //...
};

Top level cv-qualifiers on return types of non class type are ignored. Which means that even if you write:

int const foo();

You should clearly distinguish between the const usage applying to return values, parameters and the function itself.

  • It will however matter in C++11 with move-semantics involved.<\/li>
  • <\/li><\/ul>

    Consider const std::string SomeMethod() const<\/code> . It won't allow the (std::string&&)<\/code> function to be used, as it expects non-const rvalue. In other words, the returned string will always be copied.

    • <\/li><\/ul>

      Parameters<\/strong>

        The original data from parameter can't be modified anyway, as you only have copy.<\/li>
      • <\/li>
      • <\/li><\/ul>

        Function itself<\/strong>

          Thus, if it returns by reference, the reference returned must be const. Only const functions can be called on object or reference to object which is const itself. Also the mutable fields can be changed.<\/li>
        • The function can always const_cast<\/code> this<\/code> , but of course this shouldn't be done and is considered unsafe.<\/li>
        • global functions with const at the end will raise compilation error.<\/li><\/ul>

          Conclusion<\/strong>

          It will allow more cleaner code to be written, thus keeping it const-correct<\/em> . However, putting const<\/code> everywhere without giving it any thought certainly isn't the way to go.

There is little value<\/em><\/strong> in adding const<\/code> qualifications to non-reference\/non-pointer rvalues, and no point<\/em><\/strong> in adding it to built-ins.

For example, given

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

You might miss the point of Meyers' advice. The essential difference is in const<\/code> modifier for the method.

int& operator[](const int index)

The primary reason for returning values as const is so that you can't say something like foo() = 5; . This isn't actually an issue with primitive types, since you can't assign to rvalues of primitive types, but it is an issue with user-defined types (like (a + b) = c; , with an overloaded operator+ ).

I've always found the justification for that rather flimsy. You can't stop someone who's intent on writing awkward code, and this particular type of coercion has no real benefit in my opinion.

With C++11, there's actually a good deal of harm this idiom is doing: Returning values as const prevents move optimisations and should thus be avoided whenever possible. Basically, I'd now consider this an anti-pattern.

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

When that book was written, the advice was of little use, but did serve to prevent the user writing, for example, foo() = 42;<\/code> and expecting it to change something persistent.

For primitive types (like int<\/code> ), the const-ness of the result does not matter. For classes, it might change the behaviour. For example, you might not be able to call a non-const method on the result of your function:

class Bigint {
    const C foo() const { ... }
     ...
}

Bigint b;
b.foo().bar();

Look on that:

const int operator[](const int index) const

the const on end of statement. It describe that this method can be called on constants.

In the other hand when you write only

int& operator[](const int index)

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

big_int[0] = 10;

syntax.

One of your overloads is returning a reference to an item in the array, which you are then able to change.

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

The other overload is returning a value for you to use.

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

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

int foo = myBigInt[1]; // Doesn't change values inside the object.
myBigInt[1] = 2; // Assigns a new value at index `

In the example of the array-indexing operator ( operator[] ) it does make a difference.

With

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

you can use the indexing to directly change the entry in the array, eg using it like this:

mybigint[3] = 5;

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

However, as return value from functions, for simple types like eg int it doesn't matter. When it does matter is if you are returning more complex types, say a std::vector , and don't want the caller of the function to modify the vector.

The const return type is not so important here. Since int temporaries are not modifiable, there's no observable difference in using int vs const int . You would see a difference if you used a more complex object which could be modified.

There are some good answers revolving around the technicality of the two versions. For a primitive value, it doesn't make a difference.

However , I've always considered const to be there for the programmer rather than the compiler. When you write const , you're explicitly saying "this shouldn't change". Let's face it, const can usually be circumverted anyway, right?

When you return a const , you're telling the programmer that uses that function that the value shouldn't change. And if he is changing it, he's probably doing something wrong, because he/she shouldn't have to.

EDIT: I also think "use const whenever possible" is bad advice. You should use it where it makes sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM