【发布时间】:2014-02-14 17:20:02
【问题描述】:
在具有标准容器成员的类上实现移动操作的惯用方式不能是 noexcept,因此不能通过像 vector.push_back() 这样的操作移动。还是我弄错了?
获取速度
vector<Elem> data;
// ...
data.push_back( elem );
鼓励我们进行移动操作noexcept——因此在向量调整大小期间,库可以安全地将元素移动到重新分配的存储空间。
class Elem {
// ...
Elem(Elem&&) noexcept; // noexcept important for move
Elem& operator=(Elem&&) noexcept; // noexcept important for move
};
到目前为止一切顺利,现在我的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 */ }
};
这也意味着,我们也不能依赖编译器生成的移动操作,对吧?下面的完整类也没有noexcept-move-operations,因此不是“快”的,对吗?
struct Holder {
vector<int> bulk;
};
也许vector<int> 移动起来有点太简单了,但是vector<Elem> 呢?
这将对所有以容器为成员的数据结构产生重大影响。
【问题讨论】:
-
部分问题是分配器特征的未知数。你会认为
std::vector::swap()也可能是noexcept。 -
即使标准容器的成员函数没有必需的 noexcept 规范,它们也有异常保证。如果这些保证表明操作不会抛出,您可以“安全地”自己移动 ctor noexcept。
标签: c++ c++11 containers move-semantics noexcept