如何在矢量增长时执行移动语义?
我有一个特定的类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;