vector<map<move-only type>>不能用 MSVC 编译 [英] vector&lt;map&lt;move-only type&gt;&gt; does not compile with MSVC

查看:35
本文介绍了vector<map<move-only type>>不能用 MSVC 编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

制作仅移动类型映射的向量在 Windows 上似乎无法正常工作.在此处查看代码:https://godbolt.org/z/yAHmzh

Making a vector of a map of move-only types doesn't seem to work properly on Windows. See code here: https://godbolt.org/z/yAHmzh

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

// vector<vector<move-only>> works
void foo() {
    std::vector<std::vector<std::unique_ptr<int>>> outer;
    std::vector<std::unique_ptr<int>> inner;
    std::unique_ptr<int> p = std::make_unique<int>(1);
    inner.push_back(std::move(p));
    outer.push_back(std::move(inner));
}

// vector<map<move-only>> fails to compile upon inserting an element.
void bar() {
    std::vector<std::map<std::unique_ptr<int>, std::unique_ptr<int>>> vec;
    std::map<std::unique_ptr<int>, std::unique_ptr<int>> map;
    std::unique_ptr<int> p1 = std::make_unique<int>(1);
    std::unique_ptr<int> p2 = std::make_unique<int>(2);

    map.insert(std::make_pair(std::move(p1), std::move(p2)));

    // The following line fails to compile on windows. It errors with a message about
    // the unique_ptr copy constructor being explicitly deleted. This seems to only happen
    // on windows. GCC and clang have no problem with this.
    vec.push_back(std::move(map));
}

int main(int argv, char** argc)
{
    foo();

    bar();
}

GCC 和 Clang 的代码没有问题,但 MSVC 无法编译.

GCC and Clang have no problem with that code, but MSVC fails to compile.

正在寻找一种解决方法,让我可以在所有主要编译器上进行编译.

Looking for a workaround to let me do this that will compile on all major compilers.

推荐答案

强制移动语义 对于vector,我们需要通知C++(特别是std::vector)移动构造函数和析构函数不会抛出,使用 noexcept.然后 移动构造函数 将在向量增长时被调用.请参阅此说明:

To enforce move semantics for vector, we need to inform C++ (specifically std::vector) that the move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows. See this note:

为了使强异常保证成为可能,用户定义的移动构造函数不应抛出异常.例如,当需要重新定位元素时,std::vector 依赖于 std::move_if_noexcept 在移动和复制之间进行选择.

To make the strong exception guarantee possible, user-defined move constructors should not throw exceptions. For example, std::vector relies on std::move_if_noexcept to choose between move and copy when the elements need to be relocated.

有关标准中所说的更多信息,请阅读C++ 移动语义和异常

For more about what's said in the standard, read C++ Move semantics and Exceptions

如果构造函数不是noexceptstd::vector 不能使用它,因为它不能保证标准要求的异常保证.

If the constructor is not noexcept, std::vector can't use it, since then it can't ensure the exception guarantees demanded by the standard.

对于 std::map,标准不支持不说地图移动构造函数的异常安全.因此,编译器(在您的情况下,gccclang)可以将函数标记为 noexcept,与标准是否强制要求无关.

In case of std::map, the standard doesn't say anything about exception safety for move constructor of the map. So, compilers (in your case, gcc and clang) can mark functions as noexcept irrelevant of whether the Standard mandates it or not.

有关替代方案或解决方法,请参阅下面的示例(使用 gcc 测试):

For alternatives or workaround, see my example below (tested with gcc):

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

void foo(void) 
{
    std::vector<std::vector<std::unique_ptr<int>>> outer;
    std::vector<std::unique_ptr<int>> inner;
    std::unique_ptr<int> p = std::make_unique<int>(1);
    inner.emplace_back(std::move(p));
    outer.emplace_back(std::move(inner));
}

void bar(void) 
{
    std::vector<std::pair<std::unique_ptr<int>, std::unique_ptr<int>>> vec;
    std::unique_ptr<int> p1 = std::make_unique<int>(1);
    std::unique_ptr<int> p2 = std::make_unique<int>(2);

    auto pair = std::make_pair(std::move(p1), std::move(p2));

    vec.emplace_back(std::move(pair));
}

void bar2(void) 
{
    std::vector<std::unique_ptr<std::map<std::unique_ptr<int>, std::unique_ptr<int>>>> vec;
    std::unique_ptr<int> p1 = std::make_unique<int>(1);
    std::unique_ptr<int> p2 = std::make_unique<int>(2);

    auto map = std::make_unique<std::map<std::unique_ptr<int>, std::unique_ptr<int>>>();
    map->emplace(std::move(p1), std::move(p2));

    vec.emplace_back(std::move(map));
}

int main(int argc, char *argv[])
{
    foo();
    bar();
    return 0;
}

奖励:

尽可能使用emplace_back.它可以更快(但通常不是),它可以更清晰、更紧凑,但也存在一些缺陷(尤其是非显式构造函数).

Use emplace_back when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).

这篇关于vector<map<move-only type>>不能用 MSVC 编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆