命名右值引用(Named rvalue references)

编程入门 行业动态 更新时间:2024-10-28 16:24:51
命名右值引用(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]; }

很显然,我希望尽可能不要复制。 我的问题:

这段代码是否正确? 有没有更好的方法来做到这一点? 对于使用自定义类的相同方法,我是否需要定义移动构造函数?

Please pardon my lack of clarity on this topic. I am trying to create functions for inserting a big class into a vector. In this example, I use vector of ints as the big class.

#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]; }

Obviously, I want no copying to be done when possible. My questions:

Does this code do the right thing? Is there a better way of doing this? For the same approach to work with custom classes, do I need to define move constructors?

最满意答案

这段代码是否正确?

是。 为此,C ++ 11增加了std::vector::push_back(T&&) 。

有没有更好的方法来做到这一点?

你的fn(const vector<int> &v)和fn(vector<int> &&v)都做同样的事情,把参数v推到vectorOfVectors的结尾。 代替你的两个函数,你可以使用一个使用完美转发的函数模板。

template<typename T> void fn(T &&v) { vectorOfVectors.push_back(std::forward<T>(v)); }

这是如何工作的,这要归功于C ++ 11 引用崩溃规则和std::forward 。 模板类型T变为vector<int>& ,在v是左值的情况下,但在v是右值的情况下, vector<int>&& 。 参考折叠规则意味着vector<int>& &&变为vector<int>&而vector<int>&& &&变为vector<int>&& 。 这正是你想要的,调用push_back的版本,在左值的情况下执行副本,但是在右值的情况下执行移动的版本。

一个缺点是,当您出错时,这有时会导致有趣的诊断。 (“有趣”在这里意味着来自g ++或clang ++的数百行不可思议的诊断文本)。 另一个缺点是模板可能导致“转换器疯狂”的情况。

对于使用自定义类的相同方法,我是否需要定义移动构造函数?

不必要。 如果类未声明用户定义的析构函数,复制构造函数,复制赋值运算符或移动赋值运算符,则将获得隐式声明的移动构造函数。 如果类具有不可移动的数据成员或派生自无法移动或删除的类,则隐式声明的移动构造函数将被定义为已删除。

对我来说,这是有点太难记。 我不知道这是一种好的做法还是不好的做法,但我已经开始使用Foo(const Foo&)=default ,并为五个函数的其他规则使用类似的声明。 在许多情况下,我还将构造函数限定为explicit ,以避免“转换器疯狂”问题。

Does this code do the right thing?

Yes. C++11 added std::vector::push_back(T&&) for this very reason.

Is there a better way of doing this?

Your fn(const vector<int> &v) and fn(vector<int> &&v) are both doing the same thing, pushing the argument v onto the end of vectorOfVectors. In lieu of your two fn functions you could have used one function template that uses perfect forwarding.

template<typename T> void fn(T &&v) { vectorOfVectors.push_back(std::forward<T>(v)); }

How this works is thanks to the C++11 reference collapsing rules and std::forward. The template type T becomes vector<int>& in the case that v is an lvalue but vector<int>&& in the case that v is an rvalue. The reference collapsing rules means that vector<int>& && becomes vector<int>& while vector<int>&& && becomes vector<int>&&. This does exactly what you want, calling the version of push_back that does a copy in the case of an lvalue but the version that does a move in the case of an rvalue.

One downside is that this sometimes can lead to interesting diagnostics when you get things wrong. ("Interesting" here means hundreds of lines of inscrutable diagnostic text from either g++ or clang++). Another downside is that templates can result in a case of "converters gone wild".

For the same approach to work with custom classes, do I need to define move constructors?

Not necessarily. You'll get an implicitly declared move constructor if the class doesn't declare a user-defined destructor, copy constructor, copy assignment operator, or move assignment operator. The implicitly declared move constructor will be defined as deleted if the class has non-movable data members or derives from a class that can't be moved or deleted.

To me, that's a bit too much to remember. I don't know if this is a good practice or a bad one, but I've started using Foo(const Foo&)=default, with similar declarations for the other rule of five functions. I'll also qualify the constructors as explicit in many cases to avoid the "converters gone wild" problem.

更多推荐

本文发布于:2023-07-16 02:02:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1122196.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Named   rvalue   references

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!