我倾向于使用以下符号:
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与d
或get()
无关。
现在我问自己:
我的应用程序是单线程的,除了Qt GUI-Thread。
答案 0 :(得分:6)
你似乎害怕失败。当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;}
并且不违反标准的任何一个。
Elision是一种核心语言功能。不要因为你不相信会发生错误而编写错误的代码。
当您想要引用函数提供的数据时,应该通过引用进行捕获,而不是单独稳定的数据副本。如果您不了解函数的返回值的生命周期,则通过引用捕获只是不安全。
即使您知道数据会保持稳定,维护代码所花费的时间也比编写代码要多:阅读代码的人必须能够一目了然地看到您的假设成立。并且非本地错误很糟糕:对您调用的函数进行看似无害的更改不应该破坏您的代码。
最终的结果是,除非你有充分的理由不去,否则按值计算。
按值进行操作会使您和编译器更容易推理您的代码。它增加了地方。
如果你有充分的理由不这样做,那么可以参考一下。
根据具体情况,这个好理由可能不一定非常强大。但它不应该基于一个无能的编译器的假设。
应该避免过早的悲观,但应该过早优化。获取(或存储)引用而不是值应该是您在确定性能问题时所做的事情。编写干净,易于理解的代码。将复杂性推向紧密编写的类型,并使外部界面简洁明了。按值计算,因为值会使状态解耦。
优化是可替代的。通过使更多代码更简单,您可以更轻松地使用(并提高工作效率)。然后,当您确定性能重要的部分时,您可以花费那里来使代码更快。
一个很好的例子是基础代码:如果没有以性能和易用性编写,基础代码(在任何地方使用)很快就会成为性能的一般拖累。在这种情况下,您希望隐藏内部类型的复杂性,并展示一个简单易用的外部界面,并不要求用户理解这些内容。
但代码在某个随机函数中?使用值,最容易使用容器和最友好的O-notation来执行最昂贵的操作以及最简单的界面。矢量如果合理(避免过早的悲观),但不要冒出几张地图。
找到占用90%-99%的时间的代码的1%-10%,并快速完成。如果你的代码的其余部分具有良好的O符号表现(因此,对于比你测试更大的数据集,它不会变得令人震惊地变慢),你将会处于良好的状态。然后开始用荒谬的数据集进行测试,然后找到缓慢的部分。
答案 1 :(得分:5)
哪些副作用可能导致失效?
保持对类的内部状态的引用(即,延长临时的生命周期),然后调用任何非const成员函数可能会使引用无效。
将返回值分配给const引用是不是很糟糕? (特别是当我不知道功能的内部时)
我会说糟糕的做法是持有对类实例的内部状态的引用,改变类实例,并继续使用原始引用(除非记录为非-const函数不会使引用无效
答案 2 :(得分:0)
我不确定我是否正在回答您的预期,但......
const
关键字与“不安全”关键字无关。这里。
即使您返回非const引用,它也可能变为无效。 const
表示不允许修改它。例如,如果您的get()
返回const成员,或get()
本身被定义为const
,就像const some_refetence_t& get() const { return m_class_member; }
一样。
现在关于你的问题:
哪些副作用可能导致失效?
如果原始值发生变化,可能会有许多副作用。例如,假设返回的值是对堆上被删除的对象的引用...或者在原始值获得更新时缓存返回的值。所有这些都是设计问题。如果按照设计可以进行这样的情况,那么返回值应该是值(并且在缓存的情况下,它不能被缓存!:))。
将返回值分配给const引用是不是很糟糕? (特别是当我不知道函数的内部时)
同样的事情。如果按照设计,您不必修改您获得的对象(通过引用或按值),而不是最好将其定义为const
。一旦将某些内容定义为const
,编译器将确保您不会尝试在代码中以某种方式对其进行修改。
答案 3 :(得分:-1)
这是一个知道你的功能返回的问题。您还应该完全了解返回值类型及其语义。