正确命名的临时变量和右值-引用/移动
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之前,具有几乎相同的语义含义。随着右值引用和移动语义的引入,上述情况现在完全不同了。特别是,通过强制obj
为T const &
类型,您已经删除了使用move构造函数的能力,而内联形式的类型可以改为T&&
。
考虑到第一种是一种常见的范式,在标准中是否有任何东西允许优化器在第一种情况下使用move构造函数?也就是说,编译器是否可以忽略对T const &
的绑定,而将其视为T&&
,或者,正如我所怀疑的那样,这会违反抽象机器的规则吗?
问题的第二部分,要在c++ 11中正确地做到这一点(不消除命名临时),我们需要以某种方式声明一个正确的右值引用。我们也可以使用auto
关键字。那么,正确的方法是什么呢?我猜是:
auto&& obj = obj_func();
第一部分:
编译器不允许隐式地将obj
转换为非const右值,从而在调用some_func
时使用move构造函数。
第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!
我想说的是,如果某些东西符合移动条件,那么您不妨自己进行内联,而不需要额外的局部变量。毕竟,如果这样一个临时变量只被使用一次,它有什么用呢?想到的唯一场景是,如果局部变量的最后使用可以利用move语义,那么您可以将std::move
添加到最终外观中。不过,这听起来像是一个维护隐患,您真的需要一个令人信服的理由来编写它。
我不认为const &
绑定到一个临时来延长生命周期是如此普遍。事实上,在c++ 03中,在许多情况下,只需按值传递并以您所谓的内联形式: some_func( int_func(), obj_func() )
调用函数即可省略副本,因此您在c++ 11中注意到的相同问题将在c++ 03中发生(以略有不同的方式)
对于const引用绑定,如果obj_func()
返回T
类型的对象,那么上面的代码只是T obj = obj_func();
的一种繁琐的方式,除了让人们好奇为什么需要之外,它没有提供任何好处。
如果obj_func()
返回从T
派生的类型T1
,该技巧使您可以忽略确切的返回类型,但这也可以通过使用auto
关键字来实现,因此在任何一种情况下,您所拥有的都是一个本地命名变量obj
。
将obj
传递给函数的正确方法——如果您完成了它,并且函数可以将值从obj
移动到一个内部对象,实际上应该是移动:
some_func( a, std::move(obj) );
- 何时在引用或唯一指针上使用移动语义
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 设计将引用元素移动到开头的数据结构.C++
- 移动构造函数和右值引用
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- 使用移动语义:右值引用作为方法参数
- 移动类的成员作为常量引用参数传递
- 可移动但不可复制的对象:按值传递还是按引用传递?
- 垃圾回收正在移动内存中被引用的对象,破坏Unreal4引擎中的引用
- 为什么C++默认情况下不移动构造右值引用?
- 右值引用和局部变量的移动
- 为什么通过引用返回向量比通过移动返回要快得多?
- C++模板成员初始化:用右值移动构造,但用左值移动引用
- 使用反向引用移动多态成员的构造函数
- 使用 LValue 引用移动语义
- 可以从r值引用移动到临时的子对象吗
- 使用右值引用移动临时值
- 可以将std::function从右值引用移动构造到临时函数对象吗?
- 无法用通用引用移动unique_ptr
- 正确命名的临时变量和右值-引用/移动