C++ 我应该返回 const 对象吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12051012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:49:55  来源:igfitidea点击:

Should I return const objects?

c++

提问by abcdabcd987

In Effective C++Item 03, Use const whenever possible.

Effective C++Item 03 中,尽可能使用 const。

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[]does make difference from int& operator[].

const int operator[]确实与int& operator[].

But what about:

但是关于:

int foo() { }

and

const int foo() { }

Seems like that they're the same.

好像他们是一样的。

My question is, why we use const int operator[](const int index) constinstead of int operator[](const int index) const?

我的问题是,为什么我们使用const int operator[](const int index) const而不是int operator[](const int index) const

回答by James Kanze

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

忽略非类类型返回类型的顶级 cv 限定符。这意味着即使你写:

int const foo();

The return type is int. If the return type is a reference, of course, the constis no longer top level, and the distinction between:

返回类型是int。如果返回类型是引用,当然const就不再是顶层了,区别如下:

int& operator[]( int index );

and

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

is significant. (Note too that in function declarations, like the above, any top level cv-qualifiers are also ignored.)

意义重大。(还要注意,在函数声明中,像上面一样,任何顶级 cv 限定符也被忽略。)

The distinction is also relevant for return values of class type: if you return T const, then the caller cannot call non-const functions on the returned value, e.g.:

区别也与类类型的返回值有关:如果您 return T const,则调用者不能对返回值调用非常量函数,例如:

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

回答by Bartek Banachewicz

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

您应该清楚地区分适用于返回值、参数和函数本身的 const 用法。

Return values

返回值

  • If the function returns by value, the const doesn't matter, as the copy of the object is being returned. It will however matter in C++11 with move-semantics involved.
  • It also never does matter for basic types, as they are always copied.
  • 如果函数按 value返回,则 const 无关紧要,因为正在返回对象的副本。然而,在涉及移动语义的 C++11 中很重要。
  • 它对于基本类型也无关紧要,因为它们总是被复制。

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

考虑const std::string SomeMethod() const。它不允许使用该(std::string&&)函数,因为它需要非常量的右值。换句话说,返回的字符串将始终被复制。

  • If the function returns by reference, constprotects the returned object from being modified.
  • 如果函数通过引用返回,则const保护返回的对象不被修改。

Parameters

参数

  • If you pass a parameter by value, the const prevents the modification of given value by function in function. The original data from parameter can't be modified anyway, as you only have copy.
  • Note that since the copy is always created, the const has only meaning for function body, thus, it's checked only in function definition, not in declaration(interface).
  • If you pass a parameter by reference, the same rule as in return values applies
  • 如果按值传递参数,则 const 可防止在 function按函数修改给定值。参数中的原始数据无论如何都无法修改,因为您只有副本。
  • 请注意,由于始终创建副本,因此 const 仅对函数体有意义,因此,它仅在函数定义中检查,而不在声明(接口)中检查。
  • 如果通过引用传递参数,则适用与返回值相同的规则

Function itself

函数本身

  • If the function has constat the end, it can only run other constfunctions, and can't modify or allow modification of class data. 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.
  • The behavior created by the compiler changes thisreference to T const*. The function can always const_castthis, but of course this shouldn't be done and is considered unsafe.
  • It's of course sensible to only use this specifier on class methods; global functions with const at the end will raise compilation error.
  • 如果函数const末尾有,则只能运行其他const函数,不能修改或允许修改类数据。因此,如果它通过引用返回,则返回的引用必须是 const。只能在对象上调用 const 函数或对本身是 const 的对象的引用。也可以更改可变字段。
  • 编译器创建的行为将this引用更改为T const*. 该函数始终可以const_castthis,但当然不应该这样做并且被认为是不安全的。
  • 仅在类方法上使用此说明符当然是明智的;以 const 结尾的全局函数会引发编译错误。

Conclusion

结论

If your method doesn't and never will modify the class variables, mark it as const and be sure to meet all the critieria needed. It will allow more cleaner code to be written, thus keeping it const-correct. However, putting consteverywhere without giving it any thought certainly isn't the way to go.

如果您的方法不会也永远不会修改类变量,请将其标记为 const 并确保满足所有所需的标准。它将允许编写更清晰的代码,从而保持其const-correct。然而,不加思索地const随处放置当然不是要走的路。

回答by sbi

There is little valuein adding constqualifications to non-reference/non-pointer rvalues, and no pointin adding it to built-ins.

没有什么价值的加入const资格的非参考/非指针右值,并没有一点在其添加到内置插件。

In the case of user-defined types, a constqualification will prevent callers from invoking a non-constmember functionon the returned object. For example, given

用户定义类型的情况下,const限定将阻止调用者对返回的对象调用非const成员函数。例如,给定

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

then

然后

foo().resize(42);

would be forbidden, while

将被禁止,而

bar().resize(4711);

would be allowed.

将被允许​​。

For built-ins like int, this makes no sense at all, because such rvalues cannot be modified anyway.

对于像 那样的内置int函数,这完全没有意义,因为无论如何都不能修改这样的右值。

(I do remember Effective C++discussing making the return type of operator=()a constreference, though, and this is something to consider.)

(我记得C ++有效讨论作出的返回类型operator=()一个const参考,不过,这是值得考虑的问题。)



Edit:

编辑:

It seems that Scott did indeed give that advice. If so, then due to the reasons given above, I find it questionable even for C++98 and C++03. For C++11, I consider it plainly wrong, as Scott himself seems to have discovered. In the errata for Effective C++, 3rd ed., he writes (or quotes others who complained):

看来斯科特确实给出了那个建议。如果是这样,那么由于上述原因,我发现即使对于 C++98 和 C++03 也是有问题的对于 C++11,我认为这显然是错误的,正如 Scott 自己似乎已经发现的那样。在Effective C++勘误表中,第 3 版。,他写道(或引用其他抱怨的人):

The text implies that all by-value returns should be const, but cases where non-const by-value returns are good design are not difficult to find, e.g., return types of std::vector where callers will use swap with an empty vector to "grab" the return value contents without copying them.

文本暗示所有按值返回都应该是常量,但是不难找到非常量按值返回是好的设计的情况,例如,返回类型为 std::vector,其中调用者将使用带空向量的交换“抓取”返回值内容而不复制它们。

And later:

然后:

Declaring by-value function return values const will prevent their being bound to rvalue references in C++0x. Because rvalue references are designed to help improve the efficiency of C++ code, it's important to take into account the interaction of const return values and the initialization of rvalue references when specifying function signatures.

声明按值函数返回值 const 将防止它们被绑定到 C++0x 中的右值引用。由于右值引用旨在帮助提高 C++ 代码的效率,因此在指定函数签名时考虑 const 返回值和右值引用的初始化之间的交互非常重要。

回答by Andrey

You might miss the point of Meyers' advice. The essential difference is in constmodifier for the method.

您可能会错过迈耶斯建议的要点。本质区别在于const方法的修饰符。

This one is a non-const method (notice no constat the end) which means it is allowed to modify the state of the class.

这是一个非常量方法(注意最后没有const),这意味着它可以修改类的状态。

int& operator[](const int index)

This one is a const method (notice constat the end)

这个是const方法(const文末注意)

const int operator[](const int index) const

What about types of the parameter and the return value, there is a minor difference between intand const int, but it is not relevant to the point of the advice. What you should pay attention to that the non-const overload returns int&which means you can assign to it, e.g. num[i]=0, and the const overload returns non-modifiable value (no matter if the return type is intor const int).

什么类型的参数和返回值的,之间存在微小的差别intconst int,但它是不相关的咨询点。你应该注意的是非常量重载返回int&这意味着你可以分配给它,例如num[i]=0,常量重载返回不可修改的值(无论返回类型是int还是const int)。

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

在我个人看来,如果一个对象是按值传递const修饰符是多余的。这种语法更短,实现了相同的

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

回答by Kerrek SB

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 isan issue with user-defined types (like (a + b) = c;, with an overloaded operator+).

将值作为 const 返回的主要原因是你不能说类似foo() = 5;. 这实际上不是原始类型的问题,因为您不能分配给原始类型的右值,但这用户定义类型的问题(例如(a + b) = c;,带有重载的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 harmthis 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.

对于 C++11,这个习语实际上有很多危害:将值作为 const 返回会阻止移动优化,因此应尽可能避免。基本上,我现在认为这是一种反模式。

Here's a tangentially related articleconcerning C++11.

这是一篇关于 C++11 的相关文章

回答by Mike Seymour

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

写那本书时,建议没什么用,但确实有助于防止用户写作,例如,foo() = 42;并期望它改变一些持久的东西。

In the case of operator[], this can be slightly confusing if you don't also provide a non-constoverload that returns a non-constreference, although you can perhaps prevent that confusion by returning a constreference or a proxy object instead of a value.

在 的情况下operator[],如果您还没有提供const返回非const引用的非重载,这可能会有点令人困惑,尽管您也许可以通过返回const引用或代理对象而不是值来防止这种混淆。

These days, it's bad advice, since it prevents you from binding the result to a (non-const) rvalue reference.

现在,这是一个糟糕的建议,因为它会阻止您将结果绑定到(非const)右值引用。

(As pointed out in the comments, the question is moot when returning a primitive type like int, since the language prevents you from assigning to an rvalueof such a type; I'm talking about the more general case that includes returning user-defined types.)

(正如评论中所指出的,在返回像 一样的原始类型时,这个问题没有实际意义int,因为该语言阻止您分配给rvalue这种类型的 ;我说的是更一般的情况,包括返回用户定义的类型。 )

回答by Grzegorz Herman

For primitive types (like int), 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:

对于原始类型(如int),结果的常量性无关紧要。对于类,它可能会改变行为。例如,您可能无法对函数的结果调用非常量方法:

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

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

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

如果bar()是 的 const 成员函数,则上述内容被禁止C。一般来说,选择任何有意义的。

回答by Aesthete

One of your overloads is returning a referenceto 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 `

回答by Some programmer dude

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

在数组索引运算符 ( operator[])的示例中,它确实有所作为。

With

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

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

您可以使用索引直接更改数组中的条目,例如像这样使用它:

mybigint[3] = 5;

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

第二个,const int operator[](const int)运算符仅用于获取值。

However, as return value from functions, for simple types like e.g. intit 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.

然而,作为函数的返回值,对于像 egint这样的简单类型并不重要。如果您要返回更复杂的类型,例如 a std::vector,并且不希望函数的调用者修改向量,那么这很重要。

回答by Ken Wayne VanderLinde

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

const返回类型不是那么重要的位置。由于 int 临时变量不可修改,因此使用intvs没有明显差异const int。如果您使用可以修改的更复杂的对象,您会看到不同。