如何在矢量增长时执行移动语义?

我有一个特定的类A的对象的std ::向量。类是不平凡的,并有复制构造函数移动构造函数定义。

std::vector<A> myvec; 

如果我用A对象填充矢量(使用例如myvec.push_back(a) ),则使用复制构造函数A( const A&)来实例化矢量中的元素的新副本,矢量将变大。

我可以以某种方式强制A类的移动构造函数使用beging使用吗?

你需要通知C ++(特别是std::vector )你的移动构造函数和析构函数不会抛出,使用noexcept 。 然后移动构造函数将在向量增长时被调用。

这是如何声明和实现std :: vector尊重的移动构造器:

 A(A && rhs) noexcept { std::cout << "i am the move constr" <<std::endl; ... some code doing the move ... m_value=std::move(rhs.m_value) ; // etc... } 

如果构造函数不是noexcept ,std :: vector就不能使用它,因为它不能保证标准所要求的异常保证。

有关标准中所述内容的更多信息,请阅读C ++移动语义和异常

感谢Bo,他们暗示可能与例外有关。 也可以遵循Kerrek SB的建议,并尽可能使用emplace_back

编辑 ,往往默认是你想要的:移动所有可移动的,复制其余的。 明确要求,写

 A(A && rhs) = default; 

这样做,你可能会得到noexcept: 是否默认的移动构造函数定义为noexcept?

请注意,即使它支持移动语义,Visual Studio 2015及更早版本的早期版本也不支持该版本。

有趣的是,如果移动构造函数和析构函数都是noexcept,gcc 4.7.2的vector只使用move构造函数。 一个简单的例子:

 struct foo { foo() {} foo( const foo & ) noexcept { std::cout << "copy\n"; } foo( foo && ) noexcept { std::cout << "move\n"; } ~foo() noexcept {} }; int main() { std::vector< foo > v; for ( int i = 0; i < 3; ++i ) v.emplace_back(); } 

这输出了预期的:

 move move move 

但是,当我从〜foo()中移除noexcept时,结果是不同的:

 copy copy copy 

我想这也回答了这个问题 。

看来,唯一的方法(对于C + + 17和早期),执行std::vector使用移动语义重新分配是删除复制构造函数:)。 通过这种方式,它会使用你的移动构造函数或者在编译的时候尝试:)。

有许多规则, std::vector不能在重新分配时使用移动构造函数,但是不能在必须使用它的地方使用它。

 template<class T> class move_only : public T{ public: move_only(){} move_only(const move_only&) = delete; move_only(move_only&&) noexcept {}; ~move_only() noexcept {}; using T::T; }; 

生活

要么

 template<class T> struct move_only{ T value; template<class Arg, class ...Args, typename = std::enable_if_t< !std::is_same_v<move_only<T>&&, Arg > && !std::is_same_v<const move_only<T>&, Arg > >> move_only(Arg&& arg, Args&&... args) :value(std::forward<Arg>(arg), std::forward<Args>(args)...) {} move_only(){} move_only(const move_only&) = delete; move_only(move_only&& other) noexcept : value(std::move(other.value)) {}; ~move_only() noexcept {}; }; 

现场代码

你的T类必须有noexcept移动构造/ noexcept运算符和noexcept析构函数。 否则,你会得到编译错误。

 std::vector<move_only<MyClass>> vec;