繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM