vector> 无法使用 MSVC 进行编译

2023-11-22

制作仅移动类型的地图向量似乎在 Windows 上无法正常工作。 请参阅此处的代码: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 无法编译。

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


实施移动语义对于向量,我们需要通知C++(具体来说std::向量)移动构造函数和析构函数不会抛出,使用noexcept。然后移动构造函数当向量增长时将被调用。请参阅此注释:

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

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

如果构造函数不是noexcept, std::向量不能使用它,因为这样它就不能确保标准所要求的异常保证。

的情况下std::map,该标准没有提及地图的移动构造函数的异常安全性。所以,编译器(在你的情况下,gcc and clang) 可以将函数标记为 no except ,无论标准是否强制要求。

有关替代方案或解决方法,请参阅下面我的示例(已测试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;
}

BONUS:

Use emplace_back如果可能。它can更快(但通常不是),它可以更清晰、更紧凑,但也存在一些陷阱(特别是对于非显式构造函数)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vector> 无法使用 MSVC 进行编译 的相关文章

随机推荐