让函数按非内置类型的 const 值返回的用例有哪些?
最近我读到,从函数返回值来限定非内置类型的返回类型 const 是有意义的,例如:
const Result operation() {
//..do something..
return Result(..);
}
我正在努力理解这样做的好处,一旦对象被返回,肯定是调用者的选择决定返回的对象是否应该是 const?
Recently I have read that it makes sense when returning by value from a function to qualify the return type const for non-builtin types, e.g.:
const Result operation() {
//..do something..
return Result(..);
}
I am struggling to understand the benefits of this, once the object has been returned surely it's the callers choice to decide if the returned object should be const?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
基本上,这里有一个轻微的语言问题。
返回 const 右值是为了防止此类行为。然而,实际上,它弊大于利,因为现在有了右值引用,您只会阻止移动语义,这很糟糕,并且明智地使用右值和左值可能会阻止上述行为
*this
重载。另外,无论如何,你必须是一个白痴才能做到这一点。Basically, there's a slight language problem here.
Returning const rvalues is an attempt to prevent such behaviour. However, in reality, it does way more harm than good, because now that rvalue references are here, you're just going to prevent move semantics, which sucks, and the above behaviour will probably be prevented by the judicious use of rvalue and lvalue
*this
overloading. Plus, you'd have to be a bit of a moron to do this anyway.偶尔还是有用的。请参见此示例:
请注意,
operator+
返回的值通常被视为临时值。但很明显它正在被修改。这并不完全是我们想要的。如果将
operator+
的返回类型声明为const I
,则编译失败。It is occasionally useful. See this example:
Note that the value returned by
operator+
would normally be considered a temporary. But it's clearly being modified. That's not exactly desired.If you declare the return type of
operator+
asconst I
, this will fail to compile.按值返回没有任何好处。这没有道理。
唯一的区别是它阻止人们将其用作左值:
There is no benefit when returning by value. It doesn't make sense.
The only difference is that it prevents people from using it as an lvalue:
去年,我在研究双向 C++ 到 JavaScript 绑定时发现了另一个令人惊讶的用例。
它需要以下条件的组合:
Base
。Base
派生的不可复制、不可移动的类Derived
。Derived
中的Base
实例也可移动。Derived::operator const Base&()
或类似的技巧来代替公共继承。事实上,我没有为
oops_use<>
指定类型参数,这意味着编译器应该能够从参数的类型中推断出它,因此需要Base
> 实际上是Derived
的真实基础。调用 oops_use(Base) 时应发生隐式转换。为此,
create_driven()
的结果被具体化为临时Derived
值,然后将其移至oops_use
的参数中通过Base(Base&&)
移动构造函数。因此,物化临时对象现在已移出,并且断言失败。我们无法删除该移动构造函数,因为它会使
Base
不可移动。我们无法真正阻止Base&&
绑定到Derived&&
(除非我们显式删除Base(Derived&&)
,应对所有派生类执行此操作)。因此,这里唯一没有
Base
修改的解决方案是使create_driven()
返回const Derived
,以便oops_use< /code> 的参数的构造函数无法从物化临时对象中移动。
我喜欢这个例子,因为它不仅在使用和不使用
const
的情况下进行编译而没有任何未定义的行为,而且在使用和不使用const
的情况下它的行为也有所不同,并且正确的行为实际上发生在const
上仅 >const。Last year I've discovered another surprising usecase while working on a two-way C++-to-JavaScript bindings.
It requires a combination of following conditions:
Base
.Derived
deriving fromBase
.Base
insideDerived
to be movable as well.Derived::operator const Base&()
or similar tricks instead of public inheritance.The fact that I did not specify the type argument for
oops_use<>
means that the compiler should be able to deduce it from argument's type, hence the requirement thatBase<T>
is actually a real base ofDerived<T>
.An implicit conversion should happen when calling
oops_use(Base<T>)
. For that,create_derived()
's result is materialized into a temporaryDerived<T>
value, which is then moved intooops_use
's argument byBase<T>(Base<T>&&)
move constructor. Hence, the materialized temporary is now moved-from, and the assertion fails.We cannot delete that move constructor, because it will make
Base<T>
non-movable. And we cannot really preventBase<T>&&
from binding toDerived<T>&&
(unless we explicitly deleteBase<T>(Derived<T>&&)
, which should be done for all derived classes).So, the only resolution without
Base
modification here is to makecreate_derived()
returnconst Derived<T>
, so thatoops_use
's argument's constructor cannot move from the materialized temporary.I like this example because not only it compiles both with and without
const
without any undefined behaviour, it behaves differently with and withoutconst
, and the correct behavior actually happens withconst
only.