如何在 std::vector<std::map<int, std::unique_ptr<int>>> 容器中插入元素?

Rom*_*huk 1 c++ stdmap stdvector

我有std::vector<std::map<int, std::unique_ptr<int>>>容器(如果为了简化)。最初,我必须插入std::vector一定数量的std::map,每个都有一个键值对。我尝试过这样的代码:

#include <iostream>
#include <map>
#include <vector>
#include <memory>

using namespace std;

int main()
{
    vector<map<int, std::unique_ptr<int>>> data{};

    for (int x = 0; x < 10; x++)
    {
        data.emplace_back(std::make_pair(x, std::make_unique<int>(x)));
    }
}
Run Code Online (Sandbox Code Playgroud)

但这没有用。我怎样才能改变它以使其按预期工作?

编辑:我明白我的错误,我必须使用这段代码来添加元素:

std::map<int, std::unique_ptr<int>> m;
m.emplace(x, std::make_unique<int>(y));
data.emplace_back(std::move(m));
Run Code Online (Sandbox Code Playgroud)

然后,该代码可以在在线编译器中运行,但在 Visual Studio 中仍然无法运行。

Jan*_*tke 6

错误的原因是它将emplace_back尝试构建map类似的vector

std::map<int, std::unique_ptr<int>>(std::make_pair(...))
Run Code Online (Sandbox Code Playgroud)

另请参阅:std::map构造函数

然而,这是不可能的,因为接受对的构造函数正在接受std::initializer_list<std::pair<K, V>>。不存在采用单个对的构造函数。正确的做法是:

map<int, unique_ptr>{std::make_pair(...)}
Run Code Online (Sandbox Code Playgroud)

然而,构造函数std::initializer_list<T>要求 T是可复制的,而std::unique_ptr<int>不是可复制的,因此包含的T = std::pair<int, std::unique_ptr<int>>也是不可复制的。这给我们留下了以下解决方案:

#include <iostream>
#include <map>
#include <vector>
#include <memory>

int main()
{
    using map_type = std::map<int, std::unique_ptr<int>>;

    std::vector<map_type> data{};

    for (int x = 0; x < 10; x++)
    {
        for (int y = 0; y < 10; y++)
        {
            map_type m;
            m.emplace(x, std::make_unique<int>(y));
            data.emplace_back(std::move(m));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

查看实例

Visual Studio 问题

在MSVC的标准库中,不可能使用std::vector<std::map<int, std::unique_ptr<int>>. 原因是,由于强异常保证,std::vector要求其元素类型为std::nothrow_move_constructible或 可复制。

您可以看到在 MSVC STL 中std::map有非noexcept移动构造函数:

map(map&& _Right) : _Mybase(_STD move(_Right)) {}
Run Code Online (Sandbox Code Playgroud)

这是解决此问题的快速而肮脏的方法:

template <typename K, typename V>
struct nothrow_map : std::map<K, V> {
    nothrow_map() = default;
    nothrow_map(nothrow_map&& other) noexcept : std::map<K, V>(std::move(other)) {}
};

// ...

using map_type = nothrow_map<int, std::unique_ptr<int>>;
Run Code Online (Sandbox Code Playgroud)

另请参阅:(内部std::move_if_noexcept使用std::vector