为什么要用unique_ptr遍历unordered_map强制一对键为const?

问题描述 投票:0回答:1

我发现了一个编译器错误,我不明白为什么只有在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)
                      ^^^
                      ||| 

为什么仅对于唯一指针会发生此编译错误?

for-loop unique-ptr unordered-map
1个回答
0
投票

[一个朋友给了我答案,我正在分享。

答案在于允许编译器进行隐式转换(复制)的概念。

让我们看下面的简单示例:

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'来面对这样的问题并学习:)

© www.soinside.com 2019 - 2024. All rights reserved.