适当命名的临时值和右值参考/移动

时间:2011-10-04 13:52:40

标签: c++ c++11

在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();

3 个答案:

答案 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