vector<map<move-only type>>不能用 MSVC 编译 [英] vector<map<move-only type>> does not compile with 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
如果构造函数不是noexcept,std::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,标准不支持不说地图移动构造函数的异常安全.因此,编译器(在您的情况下,gcc
和 clang
)可以将函数标记为 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屋!