在C ++ 11之前,作为标准的编程习惯用法,临时工具通常被分配给变量以使代码更清晰。对于小类型,通常会生成副本,对于较大类型,可能是引用,例如:
int a = int_func();
T const & obj = obj_func();
some_func( a, obj );
现在,将其与内联形式进行比较:
some_func( int_func(), obj_func() );
在C ++ 11之前,它具有几乎相同的语义含义。随着rvalue-reference和move语义的引入,上面现在完全不同了。特别是,通过强制obj
键入T const &
,您已删除了使用移动构造函数的功能,而内联形式的类型可以是T&&
。
鉴于第一种是常见的范例,标准中是否有允许优化器在第一种情况下使用移动构造函数的东西?也就是说,编译器可能会以某种方式忽略对T const &
的绑定,而是将其视为T&&
,或者,我怀疑这会违反抽象机的规则吗?
问题的第二部分,要在C ++ 11中正确地执行此操作(不消除命名的临时值),我们需要以某种方式声明一个正确的右值引用。我们还可以使用auto
关键字。那么,正确的方法是做什么的?我的猜测是:
auto&& obj = obj_func();
答案 0 :(得分:7)
第1部分:
不允许编译器将obj
转换为非const rvalue,因此在调用some_func
时使用移动构造函数。
第2部分:
auto&& obj = obj_func();
这将创建对临时的非const引用,但在调用some_func
时不会隐式移动它,因为obj
是左值。要将其转换为右值,您应该在呼叫站点使用std::move
:
some_func( a, std::move(obj) );
答案 1 :(得分:4)
我怀疑这可以进行优化,因为不清楚你是否会再次使用临时措施:
Foo x = get_foo(); // using best-possible constructor and (N)RVO anyway
do_something(x);
do_something_else(x);
//...
如果你真的热衷于在某个地方利用移动语义(但一定要先判断一下这是否真的很重要),你可以用move
明确表达:
Foo y = get_foo();
do_oneoff_thing(std::move(y)); // now y is no longer valid!
我会说,如果某些东西有资格移动,那么你也可以自己进行内联,并且不需要额外的局部变量。毕竟,如果仅使用一次这么临时变量有什么用?想到的唯一场景是,如果 last 使用局部变量可以利用移动语义,那么您可以将std::move
添加到最终外观中。这听起来像是一种维护危险,而且你真的需要一个令人信服的理由来写这个。
答案 2 :(得分:3)
我不认为const &
绑定到临时延长生命周期是如此常见。事实上,在C ++ 03中,在许多情况下,只需传递值并在你所谓的内联形式:some_func( int_func(), obj_func() )
中调用函数,就可以省略副本,所以你在C ++ 11中注意到的同样问题会发生在C ++ 03中(以稍微不同的方式)
从const引用绑定开始,如果obj_func()
返回类型为T
的对象,则上面的代码只是执行T obj = obj_func();
的一种繁琐方式,而其他方式没有任何优势而不是让人们想知道为什么需要。
如果obj_func()
返回从T1
派生的类型T
,则该技巧可让您忽略确切的返回类型,但也可以使用auto
来实现关键字,所以在任何一种情况下,你拥有的是一个本地命名变量obj
。
将obj
传递给函数的正确方法 - 如果你已完成它,函数可以将<{1}}中的值移动到内部对象,实际上是移动:
obj