我最近一直在研究右值引用,得出的结论是,在将创建对象的完整副本的任何地方使用按值传递是非常有利的(有关完整理由,请参阅例如,在添加右值引用运算符重载时如何减少冗余代码?和想要速度?按值传递!),因为编译器可以在诸如 f(std::move(a));
的情况下自动优化副本,其中f
定义为 void f(A a);
。
随处传递值的一个负面后果是,即使在简单的情况下,所有代码都充斥着std::move
,例如:
void Object::value(A a)
{
value_ = std::move(a);
}
显然,如果我只写以下内容:
void Object::value(A a)
{
value_ = a;
}
编译器应该不难认识到,即使没有提示,a
也接近其生命周期的终点,并且不会用额外的副本来惩罚我。事实上,即使在复杂的函数中,编译器也应该能够识别这一点。
问题:
C++0x 标准是否允许此优化?
编译器是否使用它?即使在复杂的情况下,即函数由多行组成?
这种优化的可靠性如何,即我是否可以期望编译器像期望编译器应用返回值优化一样多地使用它?
C++0x 标准是否允许此优化?
不。
编译器是否使用它?即使在 复杂情况,即函数 由多行组成?
不。
这种优化的可靠性如何, 即我可以期望编译器 尽可能多地利用它 编译器应用返回值 优化?
您应该使用打印语句装饰A(const A&)
和A(A&&)
,并运行您感兴趣的测试用例。 不要忘记测试左值参数,如果这些用例是你设计的一部分。
正确的答案将取决于A
的复制和移动的成本,Object::value
实际有多少参数,以及你愿意忍受多少代码重复。
最后,对任何包含"总是"或"无处不在"等词的准则都要非常怀疑。 例如,我每隔一段时间就会使用goto
。 但是其他程序员有像"从不"这样的词与goto
相关联。 但每隔一段时间,你都无法在速度和清晰度方面击败goto
。
有时你应该偏爱一双foo(const A&) foo(A&&)
而不是foo(A)
。 而你不会的时候。 您对装饰复制和移动成员的实验将指导您。