嵌套 std::containers 个可移动对象

Nesting std::containers of movable objects

我有一个 class NoCopy 可移动,但 不可复制

我需要制作一个 3 个 NoCopy 队列的向量。我可以创建一个空的,但是没有办法添加任何元素。

我可以制作一个 std::vector<NoCopy>std::queue<NoCopy> 并填充它们。但不适用于 std::vector<std::queue<NoCopy>>.

MWE:

#include <iostream>
#include <vector>
#include <queue>

class NoCopy{
public:
    NoCopy() = default;
    NoCopy& operator = (const NoCopy&) = delete;
    NoCopy(const NoCopy&) = delete;

    NoCopy(NoCopy&&) = default;
    NoCopy& operator = (NoCopy&&) = default;

};
using QNC = std::queue<NoCopy>;

int main(void) {
    QNC q;
    q.push(std::move(NoCopy()));

    std::vector<NoCopy> ncvec;
    ncvec.emplace_back();

    std::cout << "Queue size " << q.size() << ", vector size: " << ncvec.size() << std::endl;

    std::vector<QNC> qvec;
    //????

    return 0;
}

有什么想法吗?

默认情况下,std::queue基于std::deque,不保证nothrow-movable。另一个合适的标准容器也不是,std::list;这些规则允许始终分配至少一个 node/block 的实现。 std::vector 在移动可能抛出异常时使用副本重新分配(以保证异常安全)除非类型根本不可复制,并且这两个容器也不会传播 不可复制性 从他们的元素类型,但如果你尝试就会失败。最后一个可以说是标准中的一个缺陷,因为对这种传播的期望不断上升,但修复它与对 incomplete 类型的支持不兼容:

struct Node {
  std::vector<Node> children;
  // …
};

请注意,libstdc++ 和 libc++ do 都使这两个容器不可移动(从版本 9 开始),这是允许的扩展,但 MSVC 的 STL 不.

您仍然可以使用std::vector<QNC> v(3);;构造函数“知道”永远不需要 reallocation。或者您可以提供不可复制的 wrapper 例如 ,从 std::queue 派生的 class)不可移动;前者将放弃 std::vector 的异常安全,而后者将调用 std::terminate 如果移动底层容器 确实 throw.