我什么时候应该向前移动
When should I use forward and move?
我有一个对向量进行操作的代码:
template<typename T>
void doVector(vector<T>& v, T&& value) {
//....
v.push_back(value);
//...
}
对于普通的push_back
,我需要使用forward(value)
、move(value)
还是仅使用value
(根据新的C++11)?它们如何影响性能?
例如,
v.push_back(forward<T>(value));
当第二个参数为lvalue时,当前代码将不会编译,因为T&&
将变成X&
,这意味着T
需要是X&
,这反过来意味着std::vector<T>
将变成std::vector<X&>
,这将与第一个参数std::vector<X> &
不匹配。因此,这是一个错误。
我会使用两个模板参数:
template<typename T, typename V>
void doVector(vector<T> & v, V && value)
{
v.emplace_back(std::forward<V>(value));
}
由于V
可以是与T
不同的类型,因此emplace_back
使更有意义,因为它不仅解决了问题,还使代码更通用。:-)
现在是下一个改进:由于我们使用的是emplace_back
,它从参数value
创建类型为T
的对象(可能使用构造函数),我们可以利用这一事实,使其变为可变函数:
template<typename T, typename ...V>
void doVector(vector<T> & v, V && ... value)
{
v.emplace_back(std::forward<V>(value)...);
}
这是更通用的,因为你可以用它作为:
struct point
{
point(int, int) {}
};
std::vector<point> pts;
doVector(pts, 1, 2);
std::vector<int> ints;
doVector(ints, 10);
希望能有所帮助。
-
如果您需要完美的转发意义,则使用
forward(value)
,保留l值、r值等内容。 -
转发非常有用,因为它可以帮助您避免为函数编写多个重载,其中有不同的l-val、r-val和引用参数组合
-
move(value)
实际上是一种类型的强制转换运算符,它将l值强制转换为r值 -
在性能方面,两者都避免了对对象进行额外的复制,这是主要的好处。
所以他们确实做了两件不同的事情
当你说普通的push_back时,我不确定你的意思,这是两个签名。
void push_back( const T& value );
void push_back( T&& value );
第一个你可以通过任何正常的l-val,但第二个你必须"移动"一个l-val或向前移动一个r-val。记住,一旦你移动l-val,你就不能使用它
额外的一点是,这里有一个资源似乎很好地解释了r-val-refs的概念和其他与之相关的概念。
正如其他人所建议的,你也可以切换到使用template-back,因为它实际上完美地将参数转发到对象的构造函数,这意味着你可以随心所欲地传递它。
- 当传递作为转发引用的参数时,请始终使用
std::forward
- 当传递一个r值的参数时,请使用
std::move
例如
template <typename T>
void funcA(T&& t) {
funcC(std::forward<T>(t)); // T is deduced and therefore T&& means forward-ref.
}
void funcB(Foo&& f) {
funcC(std::move(f)); // f is r-value, use move.
}
这是Scott Meyers的一段精彩视频,解释了转发引用(他称之为通用引用)以及何时使用完美转发和/或std::move
:
C++及以后的2012:Scott Meyers-C++11 中的通用参考
有关使用std::forward
的更多信息,请参阅此相关问题:使用前向的优点
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-棉眼-Cpp11 中的通用参考
这段名为IMO的视频对何时使用std::forward和何时使用std::move给出了最好的解释。它提出了通用参考的概念,这是IMO关于移动语义推理的一个非常有用的工具。
- 什么时候调用组成单元对象的析构函数
- 什么时候在C++中返回常量引用是个好主意
- 什么时候调用析构函数
- boost odeint什么时候真正调用观测者
- 编译器对数组声明大小的计算。什么时候发生?
- 什么时候最好在子进程中使用 CPU 或 I/O 密集型代码 [ C++ ]
- 您应该在什么时候创建自己的异常类型
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 什么时候可以使用常量装饰调用我的重载函数?
- unordered_map什么时候返回 -1?
- QCoreApplication什么时候有效?
- sizeof(size_t) 和 sizeof(ptrdiff_t) 什么时候会有所不同?
- 什么时候用指针调用C++类构造函数
- 我不明白在这个例子中什么时候调用构造函数
- 如果真的需要std::move,我们应该什么时候声明右值refs
- 我什么时候需要移动操作,c++
- 我什么时候应该声明一个移动构造函数而不例外
- 我什么时候应该向前移动
- 什么时候是标准::移动冗余
- 什么时候我应该提供一个移动感知过载