繁体   English   中英

在哪些情况下(const)引用返回值是不安全的?

[英]In which cases is it unsafe to (const) reference a return value?

我倾向于使用以下符号:

const Datum& d = a.calc();
// continue to use d

当calc的结果在堆栈上时,这可以工作,参见http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ 即使编译器可能在这里优化,但明确避免临时对象感觉很好。

今天我意识到,内容d成为无效数据被写入的一员后a 在这种特殊情况下,get函数只是返回对另一个成员的引用,这与写入完全无关。 像这样:

const Datum& d = a.get();
// ... some operation ...
a.somedata = Datum2();
// now d is invalid.

同样,somedata与dget()无关。

现在我问自己:

  1. 哪些副作用可能导致失效?
  2. 将返回值分配给const引用是不是很糟糕? (特别是当我不知道功能的内部)

我的应用程序是单线程的,除了Qt GUI-Thread。

你好像害怕失败。 那个auto x = some_func(); 将导致一个额外的移动构造超过auto&& x = some_func(); some_func()返回一个临时对象时。

你不应该。

如果省略失败,则表示您的编译器无能力,或者使用坦率的恶意设置进行编译。 并且你无法在恶意设置或不称职的编译器中存活:不称职的编译器可以将带有整数a+=b变成for (int i = 0; i < abs(b); ++i) {if (b>0) ++a; else --a;} for (int i = 0; i < abs(b); ++i) {if (b>0) ++a; else --a;}并且违反标准的iota。

Elision是核心语言功能。 不要因为你不相信它会发生而编写坏代码。


当您想要引用函数提供的数据时,应该通过引用捕获,而不是单独稳定的数据副本。 如果您不了解函数的返回值的生命周期,则通过引用捕获根本不安全

即使您知道数据将是稳定的,维护代码所花费的时间也比编写代码要多:阅读代码的人必须能够一目了然地看到您的假设成立。 并且非本地错误很糟糕:对您调用的函数进行看似无害的更改不应该破坏您的代码。


最终的结果是,除非你有充分的理由不去,否则按价值计算。

按值进行操作使您和编译器更容易推理您的代码。 它增加了地方。

如果你有充分的理由不这样做,那么可以参考一下。

根据具体情况,这个好理由可能不一定非常强大。 但它不应该基于一个无能的编译器的假设。

应该避免过早的悲观,但应该过早优化。 获取(或存储)引用而不是值应该是您在确定性能问题时所做的事情。 编写干净,易于理解的代码。 将复杂性推向紧密编写的类型,并使外部界面简洁明了。 按价值取物,因为价值观与国家脱钩。


优化是可替代的。 通过使更多代码更简单,您可以更轻松地使用(并提高工作效率)。 然后,当你确定部分在性能的问题,你可以付出努力使代码更快。

一个很好的例子是基础代码:基础代码(在任何地方使用)很快就会成为性能的一般拖累,如果不是考虑到性能易用性。 在这种情况下,您希望隐藏类型的复杂性,并展示一个简单易用的外部接口,不需要用户理解内部。

但代码在某个随机函数? 使用值,最容易使用容器和最友好的O符号来执行最昂贵的操作和最简单的界面。 矢量如果合理(避免过早的悲观),但不要冒出几张地图。

找到占用90%-99%时间的代码的1%-10%,并快速完成。 如果你的代码的其余部分具有良好的O符号性能(因此,对于比你测试的更大的数据集,它不会变得惊人地慢),你将处于良好的状态。 然后开始用荒谬的数据集进行测试,然后找到慢速部分。

哪些副作用可能导致失效?

持有对类的内部状态的引用(即,相对于延长临时的生命周期),然后调用任何非const成员函数可能会使引用无效。

将返回值分配给const引用是不是很糟糕? (特别是当我不知道功能的内部)

我会说不好的做法是保持对类实例的内部状态的引用,改变类实例,并继续使用原始引用(除非记录非const函数不会使引用无效)

我不确定我是否正在回答你期望听到的内容,但是...... const关键字与这里的“不安全”无关。 即使您返回非const引用,它也可能变为无效。 const表示不允许修改它。 例如,如果你的get()返回一个const成员或者get()本身被定义为const就像这个const some_refetence_t& get() const { return m_class_member; } const some_refetence_t& get() const { return m_class_member; } 现在关于你的问题:

  1. 哪些副作用可能导致失效?

如果原始值发生变化,可能会有许多副作用。 例如,假设返回的值是对堆上的对象的引用,该对象被删除...或者在原始值获得更新时缓存返回的值。 所有这些都是设计问题。 如果按照设计可以进行这样的情况,那么返回值应该是值(并且在缓存的情况下,它不能被缓存!:))。

  1. 将返回值分配给const引用是不是很糟糕? (特别是当我不知道功能的内部)

一样。 如果按照设计,您不必修改您获得的对象(通过引用或按值),而不是最好将其定义为const 一旦你定义为const ,编译器将确保你不是试图在代码中以某种方式修改它。

这是一个知道你的函数返回的问题。 您还应该完全了解返回值类型及其语义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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