命名的右值引用
Named rvalue references
请原谅我对这个话题不够清楚。我正在尝试创建用于将一个大类插入到向量中的函数。在这个例子中,我使用int的向量作为大类。
#include <vector>
#include <iostream>
using namespace std;
vector<vector<int>> vectorOfVectors;
void fn(const vector<int> &v) {
vectorOfVectors.push_back(v);
}
void fn(vector<int> &&v) {
vectorOfVectors.push_back(std::move(v));
}
int main() {
vector<int> a({1});
const vector<int> b({2});
fn(std::move(a));
fn(b);
cout<<b[0];
}
显然,我不希望在可能的情况下进行复制。我的问题:
- 这个代码做的正确吗
- 有更好的方法吗
- 对于使用自定义类的相同方法,我是否需要定义move构造函数
这个代码做的正确吗?
是的。C++11添加CCD_ 1正是出于这个原因。
有更好的方法吗?
您的fn(const vector<int> &v)
和fn(vector<int> &&v)
都在做同样的事情,将参数v
推到vectorOfVectors
的末尾。您可以使用一个使用完美转发的函数模板来代替两个fn
函数。
template<typename T>
void fn(T &&v) {
vectorOfVectors.push_back(std::forward<T>(v));
}
这要归功于C++11引用折叠规则和std::forward
。模板类型T
在std::vector::push_back(T&&)
0是左值的情况下变成vector<int>&
,而在v
是右值的情况中变成vector<int>&&
。参考折叠规则意味着vector<int>& &&
变成vector<int>&
,而vector<int>&& &&
变成vector<int>&&
。这正是你想要的,调用push_back
的版本,在左值的情况下进行复制,但在右值的情况中进行移动。
一个缺点是,当你出错时,这有时会导致有趣的诊断。(这里的"有趣"是指g++或clang++中数百行难以理解的诊断文本)。另一个缺点是模板可能导致"转换器失控"的情况。
对于使用自定义类的相同方法,我是否需要定义move构造函数?
不一定。如果类没有声明用户定义的析构函数、复制构造函数、复制赋值运算符或移动赋值运算符,则将获得隐式声明的移动构造函数。如果类具有不可移动的数据成员或派生自无法移动或删除的类,则隐式声明的move构造函数将被定义为已删除。
对我来说,这有点太难记住了。我不知道这是一个好的做法还是一个坏的做法,但我已经开始使用Foo(const Foo&)=default
,对其他五个函数的规则也有类似的声明。在许多情况下,我还会将构造函数限定为explicit
,以避免"转换器失控"的问题。
- 它确实避免了复制
a
-
是的。使用
push_back
意味着您必须构造至少两个对象,而emplace_back
和完美转发可能会做更少的工作。template<typename... Ts> auto fn(Ts &&...ts) -> decltype(vectorOfVectors.emplace_back(std::forward<Ts>(ts)...), void()) { vectorOfVectors.emplace_back(std::forward<Ts>(ts)...); }
http://melpon.org/wandbox/permlink/sT65g3sDxHI0ZZhZ
3.只要你使用push_back
,你就需要这些类是可移动构造的,以避免复制。不过,如果你能得到默认的定义,你不一定需要自己定义移动构造函数。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 如何引用基类的派生类?