首页 > 解决方案 > 嵌套可移动对象的 std::containers

问题描述

我有一个NoCopy移动不可复制的课程。

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

我可以制作一个std::vector<NoCopy>orstd::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;
}

有任何想法吗?

标签: c++containersmovable

解决方案


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

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

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

您仍然可以使用std::vector<QNC> v(3);; 构造函数“知道”永远不需要重新分配。或者您可以提供一个不可复制或不可移动的包装器例如,派生自 的类);std::queue前者将放弃 的异常安全性std::vector,而后者将std::terminate在移动底层容器确实抛出时调用。


推荐阅读