102

我有std::vector一个特定类的对象A。该类是非平凡的,并且定义了复制构造函数移动构造函数。

std::vector<A>  myvec;

如果我用对象填充向量A(使用 eg myvec.push_back(a)),向量的大小会增加,使用复制构造函数A( const A&)来实例化向量中元素的新副本。

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

4

3 回答 3

143

您需要通知 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...
}

如果构造函数不是noexceptstd::vector则不能使用它,因为这样就无法确保标准要求的异常保证。

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

Bo 暗示这可能与例外有关。还可以考虑 Kerrek SB 的建议并emplace_back尽可能使用。它可以更快(但通常不是),可以更清晰、更紧凑,但也存在一些缺陷(尤其是非显式构造函数)。

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

A(A && rhs) = default;

这样做,您将尽可能获得 noexcept:默认的 Move 构造函数是否定义为 noexcept?

请注意,早期版本的 Visual Studio 2015 和更早版本不支持这一点,即使它支持移动语义。

于 2012-01-14T19:50:00.577 回答
17

有趣的是,gcc 4.7.2 的向量仅在移动构造函数和析构函数都是noexcept. 一个简单的例子:

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

但是,当我从中删除noexcept~foo(),结果是不同的:

copy
copy
copy

我想这也回答了这个问题

于 2013-03-14T19:12:50.193 回答
-1

看来,std::vector在重新分配上强制使用移动语义的唯一方法(对于 C++17 和早期版本)是删除复制构造函数:)。通过这种方式,它将在编译时使用您的移动构造函数或尝试死亡:)。

有许多规则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析构函数。否则你会得到编译错误。

std::vector<move_only<MyClass>> vec;
于 2017-10-30T15:53:41.960 回答