Kil*_*Kid 7 c++ move-constructor
我最近从移动构造函数中偶然发现了一些奇怪的行为(从我的观点来看很奇怪).使用GCC和Visual Studio进行编译时,结果会有所不同.我想听听这种行为的解释,不要认为这是一个bug,但可能是特定于编译器的.
请考虑以下代码:
#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;
}
Run Code Online (Sandbox Code Playgroud)
所以我在创建元素时将迭代器存储到map元素中的map的末尾.我也参考了它以便稍后进行比较.来自std :: unordered_map :: emplace:
如果容器中没有带键的元素,则使用给定的args将新元素插入到就地构造的容器中.
小心使用emplace可以构建新元素,同时避免不必要的复制或移动操作.
使用默认移动构造函数,存储在map元素中的迭代器和我的引用是相同的:
Test(Test &&) = default;
Run Code Online (Sandbox Code Playgroud)
结果是true在GCC和true在VS. 现在,如果我将移动构造函数更改为:
Test(Test &&) {}
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会仍然返回 true但VS返回false
以防万一尝试使用c ++ 17,结果相同.那么有人可以解释一下这里发生了什么吗?
在这一行中:
m.emplace(0, Test{ it });
Run Code Online (Sandbox Code Playgroud)
...新插入的Test对象是从 构造的std::forward<Test>(Test{ it }),因此确实调用了移动构造函数(由于转发,复制省略在这里不起作用)。如果想Test直接构建,可以使用m.emplace(0, it)。
现在我们可以看到
随着Test(Test &&) = default;,由 指定的临时对象Test{ it }.v被移入m.at(0).v。如果it仍然有效(不保证),则m.at(0).v.end() == it计算结果为true;否则程序会导致未定义的行为。
使用Test(Test &&) {},m.at(0).v进行值初始化,并it随着 指定的临时对象Test{ it }.v被销毁而失效。该程序导致未定义的行为。
在libstdc++的实现中,不同unordered_maps的结束迭代器具有相同的值(类似于std::istream_iterator),因此GCC的行为是合理的。
| 归档时间: |
|
| 查看次数: |
149 次 |
| 最近记录: |