在下面的代码中,我试图编辑unordered_map的内容:
class A {
public:
A() {std::cout << "Constructor called, address=" << this << std::endl;val=1;}
int val;
};
void main(void) {
std::unordered_map<int,A> um;
for (int i=0;i<3;i++)
std::cout << "um[" << i << "]=" << &(um[i]) << ", val=" << um[i].val << std::endl;
for (auto it : um)
std::cout << "&it.second=" << &(it.second) << ", val=" << it.second.val << std::endl;
int index = 1;
for (auto um_it : um)
um_it.second.val = index++;
for (int i=0;i<3;i++)
std::cout << "um[" << i << "]=" << &(um[i]) << ", val=" << um[i].val << std::endl;
for (auto it : um)
std::cout << "&it.second=" << &(it.second) << ", val=" << it.second.val << std::endl;
}
以上的输出是:
Constructor called, address=0x8dcb2c
um[0]=0x8dcb2c, val=1
Constructor called, address=0x8dc7ac
um[1]=0x8dc7ac, val=1
Constructor called, address=0x8dc42c
um[2]=0x8dc42c, val=1
&it.second=0x7ffc62f24484, val=1
&it.second=0x7ffc62f24484, val=1
&it.second=0x7ffc62f24484, val=1
um[0]=0x8dcb2c, val=1
um[1]=0x8dc7ac, val=1
um[2]=0x8dc42c, val=1
&it.second=0x7ffc62f24484, val=1
&it.second=0x7ffc62f24484, val=1
&it.second=0x7ffc62f24484, val=1
当我用以下代码替换编辑代码时:
int index = 1;
for (auto um_it = um.begin(); um_it != um.end(); ++um_it)
um_it->second.val = index++;
输出结果为:
Constructor called, address=0x9d8b2c
um[0]=0x9d8b2c, val=1
Constructor called, address=0x9d87ac
um[1]=0x9d87ac, val=1
Constructor called, address=0x9d842c
um[2]=0x9d842c, val=1
&it.second=0x7fffd2201c34, val=1
&it.second=0x7fffd2201c34, val=1
&it.second=0x7fffd2201c34, val=1
um[0]=0x9d8b2c, val=3
um[1]=0x9d87ac, val=2
um[2]=0x9d842c, val=1
&it.second=0x7fffd2201c34, val=1
&it.second=0x7fffd2201c34, val=2
&it.second=0x7fffd2201c34, val=3
我从结果中了解到,在第一个版本中,代码会影响对象的副本,但这看起来很奇怪。我还期望调用复制构造函数,但事实并非如此。如果有人可以解释幕后发生的事情以及在不制作冗余副本的情况下迭代unordered_map的最佳方法,我会感到高兴。
答案 0 :(得分:4)
在行中:
for (auto um_it : um)
um_it
不是迭代器。它是地图中值的副本。然后,您可以在循环体中修改该副本,从而保持映射不变。这将为每次迭代调用A
的复制构造函数。
相反,您可以参考:
for ( auto& um_item : um )
当um_item
引用地图中的条目时。 (当使用基于范围的for循环时,您无法访问底层迭代器,您只能访问每个元素或其副本)。