换句话说,当i
是map<K,V>::iterator
时,请执行以下操作以提供预期的语义(即,它会修改地图):
*i = make_pair(k, v);
i->first = k;
i->second = v;
更新:前两行无效,因为operator*
的返回值是(可转换为?)a pair<const K, V>
。第三行怎么样?
假设对这三个人的是答案,这意味着:
map<K,V>
个元素都存储为某个地方的pair<K,V>
map<K,V>::iterator::operator*
返回。在这种情况下,operator->
如何实施?答案 0 :(得分:4)
我试图通过标准来追踪这一点:
对于map<Key,T>
value_type
为pair<const Key,T>
每23.3.1 / 2
map类支持双向迭代器,按照23.3.1 / 1
双向迭代器满足前向迭代器的要求,符合24.1.4 / 1
对于带有a
value_type
的转发迭代器T
,表达式*a
会返回 T&amp; (不是“可转换为”的类型T“,正如其他一些迭代器所做的那样)(24.1.3中的表74)
因此,要求是返回对pair的引用,而不是其他代理类型。
答案 1 :(得分:3)
地图几乎就像一对配对。是的,它的迭代器可能被实现为指向具有pair<const K,V>
的节点的指针。 然而您的代码无效,因为这些值实际上属于pair<const K, V>
类型,因此您无法分配给first
。
*我返回pair<const K, V>&
或某些行为类似的代理(无法找到标准中最后一个声明的备份)。您可以通过重载operator ->
来实现此类代理。
答案 2 :(得分:1)
首先,从技术上讲,一元*
运算符在这种情况下求值为左值。但是,C中的术语lvalue基本上指的是在存储(存储器)中具有位置(地址)的东西。在C ++术语中,甚至函数都是 lvalues 。所以,再次,在上面的例子中,一元*
产生一个左值。如果您愿意,可以使用该左值的地址,即您可以评估&*i
,&i->first
和&i->second
(假设内置的一元&
)
其次,由于您的原始示例涉及赋值,因此您必须实际谈论可修改的左值。你看, lvalue 的属性本身与可分配的关系很少。要使用内置赋值运算符,需要可修改的左值。从解除引用的迭代器获得的是value_type
std::map
。如你所知,它是一对具有const限定的第一个成员。这会自动使第一个成员不可修改,这使得整个对无法通过内置赋值运算符进行修改。正如您自己观察到的那样,该对中的第二个成员是可修改的。
因此,在这种情况下,取消引用运算符再次返回左值。这个左值作为一个整体是不可修改的,它的第一个成员也是不可修改的。它的第二个成员是可修改的左值。
至于你关于如何存储std::map
元素的假设,我会说在一个典型的实现中,它们将被存储为pair<const K, V>
个对象,即dereference运算符所评估的对象。通常,映射在初始化之后不需要修改该对的键部分,因此它不应该遇到任何问题,因为该对的第一个成员是const限定的。
答案 3 :(得分:1)
map<K,V>::iterator i = my_map.begin();
*i = make_pair(k, v); // invalid, you cannot assign to a pair<const K,V>&
i->first = k; // invalid cannot write to const
i->second = v; // valid