返回常量值的目的是什么?

172

这里的const有什么作用?

const Object myFunc(){
    return myObject;
}
我刚开始阅读《Effective C++》,其中第3条建议使用const,同时谷歌搜索也提到了一些类似的建议,但也有反例。我无法理解在这里使用const会比不使用更好。假设我们希望返回值,保护返回值似乎没有任何理由。为什么要这样做的一个例子是防止返回值被意外地转换成bool类型。实际上,问题在于应该使用explicit关键字来防止隐式的bool转换。
在这里使用const可以防止未经分配使用临时对象。因此,我无法对这些对象执行算术表达式。似乎没有任何情况下未命名的const会有用。
使用const带来了什么好处?在什么情况下使用它更好呢?
编辑:将算术示例更改为任何在赋值之前可能要执行的修改对象的函数。

1
是的,您可以对const对象执行算术运算,因为算术运算符应该是const的,并且还应返回const对象。 - Seth Carnegie
不确定是否值得回答,但返回const值的另一个副作用是它无法移动。你几乎唯一能做的修改(该值)的方法是将其复制到非const变量中。我不知道它是否可以用于某些特定的东西,但就是这样。 - alfC
4个回答

166

假设你可以对一个对象执行可能昂贵的非常量操作,在返回常量值的情况下可以防止你在临时对象上意外调用此操作。想象一下,如果+返回一个非常量值,你可以这样写:

(a + b).expensive();

然而,在C++11时代,强烈建议将返回值作为非常量来使用,以便充分利用只对非常量右值有意义的右值引用。

总之,这种做法确实有其合理性,但本质上已经过时了。


6
Herb Sutter曾建议对于非基本类型的变量返回const值,但我认为你是正确的,这个建议现在已经过时了。 - Fred Larson
44
@FredLarson:是的,在一本14年前的书中 :-S - Kerrek SB
1
这个回答意味着通过const-value返回意味着const &&,但这真的是正确的吗?例如,VS13允许我将int&& var绑定到返回const int的函数。"调用返回非引用类型的函数的结果是prvalue"。 - Karlis Olte
1
@user64985:我不太明白你的意思。prvalue 是 rvalue。 - Kerrek SB
1
我提出了一个问题。那个引用是我在标准中找到的唯一相关信息,它没有提到const。 - Karlis Olte
显示剩余3条评论

65

从函数中返回const值是相当无意义的。

让它对你的代码产生任何影响都是困难的:

const int foo() {
   return 3;
}

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

const int foo() {
   return 3;
}

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

// error: lvalue required as left operand of assignment

虽然你可以注意到返回类型是用户定义类型

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

这是否对任何人有益仍是个问题。

返回一个引用是不同的,但除非Object是某个模板参数,否则您不会这样做。


1
你能详细说明第一个例子吗?对我来说,将返回值声明为const,但仍能将其赋值给非const变量是毫无意义的。 - Ivaylo Toskov
3
所有你需要的解释都在这个例子里,特别是注释“copies happily”。考虑一下const int x = 4; int y = x;,这也是完全没问题的。 - Lightness Races in Orbit
@LightnessRacesinOrbit:哇,标准出现漏洞了。应该能够创建一个无法复制、读取或更新的对象。对于“x=4”的小值来说是可以实现的。 - user4624979
@nocomprende:为什么?那有什么用处? - Lightness Races in Orbit
@nocomprende:你的昵称非常贴切,因为我不知道你在说什么。 - Lightness Races in Orbit
显示剩余10条评论

12

它确保返回的对象(此时是一个RValue)无法被修改。这确保了用户无法执行如下操作:

myFunc() = Object(...);

如果myFunc返回引用,这将非常有效,但当返回值时几乎肯定是一个错误(并且可能不会被编译器捕获)。当然,在C++11中使用rvalue时,这个惯例不如早期那么有意义,因为const对象无法被移动,所以这可能对性能产生很重的影响。


那并没有解释 const - Nicol Bolas
@Nicol Bolas:它为什么没有解释const?如果返回类型是“Object”,则代码示例将编译,但如果返回类型是“const Object”,则不会编译。 - Grizzly
你的意思是“用C++11中的_xvalues_”吧?(我知道_xvalues_和_prvalues_都是_rvalues_,但是在C++11中新引入的_xvalues_才是重要的区别。) - CB Bailey

-3

它可以用作返回对私有常量数据类型的引用的包装函数。例如,在链表中,您有常量尾部和头部,如果您想确定节点是否为尾部或头部节点,则可以将其与该函数返回的值进行比较。

虽然任何优化器都很可能将其优化掉...


4
没有什么可优化的,常量性是一种编译时的安全机制。 - Paul Manta
看起来你在考虑返回一个常量 _引用_,所以这不相关。可能应该通过返回任何哨兵节点指针/迭代器类型的值副本来完成,除非复制很昂贵,否则不需要返回任何引用。如果返回一个值,就没有必要/意义使其 const,所以回到原点。 - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接