[英]Proper named temporaries and rvalue-reference/move
在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();
第1部分:
不允许编译器将obj
转换为非const rvalue,因此在调用some_func
时使用移动构造函数。
第2部分:
auto&& obj = obj_func();
这将创建一个对临时的非const引用,但是当调用some_func
时它不会被隐式移动,因为obj
是一个左值 。 要将其转换为右值,您应该在调用站点使用std::move
:
some_func( a, std::move(obj) );
我怀疑这可以被优化,因为不清楚你是否会再次使用临时:
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!
我会说,如果某些东西有资格移动,那么你也可以自己进行内联,并且不需要额外的局部变量。 毕竟,如果仅使用一次这么临时变量有什么用? 想到的唯一场景是,如果最后一次使用局部变量可以利用移动语义,那么您可以将std::move
添加到最终外观。 这听起来像是一种维护危险,你真的需要一个令人信服的理由来写这个。
我不认为const &
绑定到临时延长寿命是如此常见。 事实上,在C ++ 03中,在许多情况下,只需传递值并在你所谓的内联形式中调用函数就可以省略副本: some_func( int_func(), obj_func() )
,所以您在C ++ 11中注意到的同样问题将出现在C ++ 03中(以稍微不同的方式)
从const引用绑定开始,如果obj_func()
返回类型为T
的对象,则上面的代码只是执行T obj = obj_func();
一种麻烦的方式T obj = obj_func();
除了让人们想知道为什么需要这样做之外,它没有任何优势。
如果obj_func()
返回一个从T
派生的类型T1
,那么这个技巧可以让你忽略确切的返回类型,但这也可以通过使用auto
关键字来实现,所以在任何一种情况下,你拥有的是一个本地命名变量obj
。
将obj
传递给函数的正确方法 - 如果你已完成它,并且函数可以将值从obj
移动到内部对象,则实际上是移动 :
some_func( a, std::move(obj) );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.