我发现了一个编译器错误,我不明白为什么只有在std :: map和std :: unique_ptr时才会发生。
假设我们有以下未加注释的地图对象及其迭代代码:
std::unordered_map<uint32_t, std::shared_ptr<char>> map;
for (const std::pair<uint32_t, std::shared_ptr<char>>& item : map)
{
// do something
}
这编译得很好,但是如果我们按如下方式使用唯一指针而不是共享指针,那么我们将得到有关迭代对类型的编译器错误:
std::unordered_map<uint32_t, std::unique_ptr<char>> map;
for (const std::pair<uint32_t, std::unique_ptr<char>>& item : map)
{
// do something
}
error C2440: 'initializing': cannot convert from 'std::pair<const _Kty,_Ty>' to
'const std::pair<uint32_t,std::unique_ptr<char,std::default_delete<_Ty>>>
出现此错误后,我们可以将'const'添加到密钥类型中并进行编译。
for (const std::pair<const uint32_t, std::unique_ptr<char>>& item : map)
^^^
|||
为什么仅对于唯一指针会发生此编译错误?
[一个朋友给了我答案,我正在分享。
答案在于允许编译器进行隐式转换(复制)的概念。
让我们看下面的简单示例:
const char x = 4;
const char& r = x; // r is reference for x. Checking their addresses yields the same
// address.
const int& ir = c; // implicit creation of object + conversion(copy).
// ir is different type of x, therefor compiler does implicit
// conversion(copy): it creates behind the scene an object of int,
// convert x into this temporary object. The temporary int object is
// then bound to the reference ir. Checking addresses of ir and x
// yields different addresses because ir is reference of the temporary
// object, not to x
因此,即使我们使用参考-计划只是指向现有对象,我们实际上可能有一个对象构造+副本(如果类型不同并且它们之间存在转换)。
我在问题中给出的循环中也发生了同样的事情:
std::unordered_map<uint32_t, std::shared_ptr<char>> map;
for (const std::pair<uint32_t, std::shared_ptr<char>>& item : map)
{
// do something
}
而地图上保存的真实对象是]类型的>
std::pair<const uint32_t, std::shared_ptr<char>>
循环使用不同类型的引用:
std::pair<uint32_t, std::shared_ptr<char>>
因此,在幕后,每次迭代都会隐式构造一个新的临时对象,并执行复制操作以进行转换。
不仅效率不高,而且当值是unique_ptr时也无法编译,因为该转换会复制并且无法复制unique_ptr。
这就是为什么使用'auto'可以为您节省这样的错误,
std::unordered_map<uint32_t, std::shared_ptr<char>> map; for (const auto& item : map) { // do something }
我本人有时更喜欢玩和使用显式形式而不是'auto'来面对这样的问题并学习:)