如果类包含标准容器,是否可以标记类move- operation noexcept?

tow*_*owi 9 c++ containers move-semantics noexcept c++11

使用标准容器成员对类实现移动操作的惯用方法不能noexcept,因此不能通过类似的操作移动vector.push_back().还是我弄错了?

为了加快速度

vector<Elem> data;
// ...
data.push_back( elem );
Run Code Online (Sandbox Code Playgroud)

我们鼓励我们进行移动操作noexcept- 因此在向量调整大小期间,库可以安全地将元素移动到重新分配的存储.

class Elem {
    // ...
    Elem(Elem&&) noexcept;            // noexcept important for move
    Elem& operator=(Elem&&) noexcept; // noexcept important for move
};
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,现在我的elems可以更快地被推回.

但是:如果我添加一个容器作为成员,我的班级仍可以标记为noexcept-move吗?所有标准容器都没有移动noexcept!

class Stuff {
    vector<int> bulk;
    // ...
    Stuff(Stuff&& o)  // !!! no noexcept because of vector-move  
      : bulk(move(o.bulk))
      {}
    Stuff& operator=(Stuff&&) // !!! no noexcept...
      { /* appropriate implementation */ }
};
Run Code Online (Sandbox Code Playgroud)

这也意味着,我们也可以不依赖编译器生成的移动操作,对吧?以下完整的类也没有noexcept-move-operations,因此不是"快",对吗?

struct Holder {
    vector<int> bulk;
};
Run Code Online (Sandbox Code Playgroud)

可能vector<int>有点太简单了,但是怎么样vector<Elem>

这将对容器作为成员的所有数据结构产生巨大影响.

How*_*ant 9

真的,我感受到了你的痛苦.

一些std :: implementation会将容器的移动成员标记为noexcept(至少以allocator属性为条件)作为扩展.您可以调整代码以自动利用这些扩展,例如:

class Stuff {
    std::vector<int> bulk;
    // ...
public:
    Stuff(Stuff&& o)
      noexcept(std::is_nothrow_move_constructible<std::vector<int>>::value)
      : bulk(std::move(o.bulk))
      {}
    Stuff& operator=(Stuff&&)
      noexcept(std::is_nothrow_move_assignable<std::vector<int>>::value)
      { /* appropriate implementation */ }
};
Run Code Online (Sandbox Code Playgroud)

你甚至可以测试你的类型是否有noexcept移动成员:

static_assert(std::is_nothrow_move_constructible<Stuff>::value,
                     "I hope Stuff has noexcept move members");
static_assert(std::is_nothrow_move_assignable<Stuff>::value,
                     "I hope Stuff has noexcept move members");
Run Code Online (Sandbox Code Playgroud)

特别是libc ++在分配器允许的情况下,对所有容器都有noexcept移动成员,并且std::allocator始终允许容器移动成员为noexcept.