作为rvalue引用的新手并移动语义,我试图从std::vector
派生一个简单的模板类(我保证我会对缺少虚拟析构函数小心)。为了继承"移动构造函数,我只是调用基类对应的std::move
,
template <typename T>
class Vec: public std::vector<T> {
public:
...
//move ctors
Vec(Vec&& v): std::vector<T>(v) { //move extra members with std::move }
explicit Vec(std::vector<T>&& v): std::vector<T>(v) { //same as above }
...
};
基于我对C ++的理解,它似乎值得信赖。但是,我对移动赋值运算符的方法信心不足,
//assignment
Vec& operator=(const Vec& v) {
std::vector<T>::operator=(v);
if (&v != this)
//copy extra members
return *this;
}
//move assignment
Vec& operator=(Vec&& v) {
std::vector<T>::operator=(v);
//move extra members with std::move
return *this;
}
这是实现我想要的万无一失的方式吗?在良好实践方面是否有更好的选择?
答案 0 :(得分:4)
似乎值得信赖......
似乎值得信赖。但事实并非如此。你看,这个:
Vec(Vec&& v)
是一个移动构造函数。所以它会被rvalue调用。但是一旦我们进入这里,v
就是一个左右!经验法则:如果它有名字,那就是左值。所以这一部分:
: std::vector<T>(v)
不会调用std::vector
的 move 构造函数。它调用 copy 构造函数。您需要将v
明确地转换为右值才能做正确的事情:
Vec(Vec&& v) : std::vector<T>(std::move(v)) { }
explicit Vec(std::vector<T>&& v): std::vector<T>(std::move(v)) { }
或者,更好的是:
Vec(Vec&& ) = default;
同样,编写赋值运算符的简单方法只是default
- 它们:
Vec& operator=(Vec const& ) = default;
Vec& operator=(Vec&& ) = default;
但如果你真的有特殊的逻辑,那么请确保你也记得在那里施放rvalue:
Vec& operator=(Vec&& v) {
std::vector<T>::operator=(std::move(v));
// stuff
return *this;
}
甚至更好,将您的特殊逻辑转移到一个独立的单元,以便default
- 仍然是正确的。