【发布时间】:2018-12-15 15:14:35
【问题描述】:
我最近从 move 构造函数中偶然发现了一些奇怪的行为(在我看来很奇怪)。使用 GCC 和 Visual Studio 编译时结果不同。我想听听这种行为的解释,不要认为这是一个错误,但可能是特定于编译器的。
考虑以下代码:
#include <iostream>
#include <unordered_map>
struct Test
{
std::unordered_map<int, int> v;
std::unordered_map<int, int>::iterator vend;
Test(std::unordered_map<int, int>::iterator &it)
: vend { v.end() }
{
it = this->vend;
};
Test() = delete;
Test(Test const &) = delete;
Test(Test &&) = default; // <- line in question
};
int main()
{
std::unordered_map<int, int>::iterator it;
std::unordered_map<int, Test> m;
m.emplace(0, Test{ it });
std::cout << std::boolalpha << (m.at(0).v.end() == it) << "\n";
return 0;
}
所以我在创建元素时将迭代器存储到地图元素中的地图末尾。我也参考了它,以便稍后进行比较。来自std::unordered_map::emplace:
将新元素插入就地构造的容器中 如果容器中没有带有键的元素,则给定 args。
小心使用 emplace 允许在构造新元素的同时 避免不必要的复制或移动操作。
使用默认的move构造函数,map元素中存储的迭代器和我的引用是一样的:
Test(Test &&) = default;
Results 在 GCC 中是 true,在 VS 中是 true。现在,如果我将移动构造函数更改为:
Test(Test &&) {}
GCC still returnstrue 但VS返回false
以防万一尝试使用 c++17,结果相同。那么谁能解释一下这里发生了什么?
【问题讨论】:
-
Test{it}作为外参数集it。 emplace 做了一个动作,这将使迭代器无效。将m.at(0).v.end()与无效的it进行比较。谁知道会发生什么?许个愿。 -
@Eljay 地图内的迭代器将被保留,因为他返回的迭代器是在 emplace 内移动的地图......如果我错了,请纠正我
-
@Kilzone,在这种情况下,您认为哪个构造函数会用于“就地构造”?
-
@Eljay - 关联容器迭代器不会在移动时失效,这也包括结束迭代器。
-
回到 Killzone Kid 的问题,我不知道
std::unordered_map<int, int>::iterator根据 C++ 标准对默认构造做了什么。似乎一个平台将其初始化为与end()相同(或者您很幸运),而另一个平台使其处于未初始化状态。如果您输入: vend{std::move(rhs.vend)},您可能会得到更一致的结果。
标签: c++ move-constructor