map::iterator 会产生左值吗?
换句话说,当 i
是 map
时,以下内容是否提供预期的语义(即它修改映射)
*i = make_pair(k, v);
i->first = k;
i->second = v;
:?
更新:前两行无效,因为 operator*
的返回值是(可转换为?)pair
。第三行呢?
假设对这三个问题的回答是是,这意味着:
map
元素存储为对
code> 某处,- 或者有一些聪明的代理类,
map
返回。在这种情况下,::iterator::operator* operator->
是如何实现的?
In other words, when i
is a map<K,V>::iterator
, do the following provide the expected semantics (ie. it modifies the map):
*i = make_pair(k, v);
i->first = k;
i->second = v;
?
Update: The first two lines are invalid, since the return value of operator*
is (convertible to?) a pair<const K, V>
. What about the third line ?
Assuming a yes answer to the three, this would imply that:
- Either
map<K,V>
elements are stored as apair<K,V>
somewhere, - Or there is some clever proxy class which
map<K,V>::iterator::operator*
returns. In this case, how isoperator->
implemented ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我试图通过标准来追踪这一点:
对于
map
,value_type
是pair
per 23.3.1/2map 类支持双向迭代器,per 23.3.1/1
双向迭代器满足前向的要求迭代器,根据 24.1.4/1
对于具有
value_type
的前向迭代器a
>T
,表达式*a
返回 T& (不是像其他一些迭代器那样“可转换为 T”的类型)(表 74 24.1.3)因此,要求是返回对对的引用,而不是其他代理类型。
I tried to track this down through the standard:
For a
map<Key,T>
thevalue_type
ispair<const Key,T>
per 23.3.1/2The map class supports bidirectional iterators, per 23.3.1/1
bidirectional iterator satisfies the requirements for forward iterators, per 24.1.4/1
For a forward iterator
a
withvalue_type
T
, expression*a
returns T& (not a type "convertible to T", as some other iterators do) (Table 74 in 24.1.3)Therefore, the requirement is to return a reference to pair, and not some other proxy type.
地图几乎就像一组对。是的,它的迭代器可能被实现为一个指向带有
pair
的节点的指针。 但是您的代码无效,因为这些值实际上是pair
类型,因此您无法分配给first
。*i 返回
pair&
或一些行为类似于此类型的代理(无法找到标准中最后一个声明的备份)。您可以通过重载operator ->
来实现此类代理。map is almost like a set of pairs. Yes, it's iterator is probably implemented as a pointer to a node with a
pair<const K,V>
. However your code is invalid, because the values are actually of typepair<const K, V>
so you can't assign tofirst
.*i returns
pair<const K, V>&
or some proxy that behaves like this type(can't find a backup of the last claim in the standard). You can implement such proxies by overloadingoperator ->
.首先,从技术上讲,在这种情况下,一元
*
运算符的计算结果为左值。然而,C 语言中的术语“左值”基本上表示在存储(内存)中具有位置(地址)的内容。在 C++ 术语中,甚至函数也是左值。因此,同样,在上面的示例中,一元*
产生一个左值。如果您愿意,您可以获取该左值的地址,即您可以计算&*i
、&i->first
和&i->second
(假设内置一元&
)。其次,由于您最初的示例涉及赋值,因此您实际上必须谈论可修改的左值。您会看到,左值属性本身与可赋值关系不大。要使用内置赋值运算符,您需要一个可修改的左值。从解除引用的迭代器中得到的是
std::map
的value_type
。如您所知,它是一对具有 const 资格的第一个成员。这会自动使第一个成员不可修改,并且使整个对不可被内置赋值运算符修改。正如您已经观察到的那样,该对中的第二个成员是可以修改的。因此,在这种情况下,解引用运算符再次返回左值。这个左值作为一个整体是不可修改的,它的第一个成员也是不可修改的。它的第二个成员是可修改的左值。
至于您关于如何存储
std::map
元素的假设,我想说,在典型的实现中,它们将存储为pair
对象,即解引用运算符的计算结果。通常,映射在初始化后不需要修改该对的关键部分,因此,由于该对的第一个成员是 const 限定的,因此它不应该遇到任何问题。Firstly, technically the unary
*
operator evaluates to an lvalue in this case. However, the term lvalue in C basically designates something that has location (address) in storage (memory). In C++ terminology even functions are lvalues. So, again, in your example above the unary*
yield an lvalue. You can take the address of that lvalue, if you wish to do so, i.e. you can evaluate&*i
,&i->first
and&i->second
(assuming the built-in unary&
).Secondly, since you original example involves assignment, you must be actually talking about modifiable lvalues. You see, the property of being lvalue by itself has very little to do with being assignable. To use the built-in assignment operator, you need a modifiable lvalue. What you get from a dereferenced iterator is
value_type
ofstd::map
. It is a pair with a const-qualified first member, as you know already. This automatically makes the first member non-modifiable, and this makes the entire pair non-modifiable by the built-in assignment operator. The second member of the pair is modifiable, as you observed yourself already.So, once again, the dereference operator in this case returns an lvalue. This lvalue is non-modifiable as a whole, and its first member is non-modifiable as well. Its second member is a modifiable lvalue.
As for your assumption about how the elements of
std::map
are stored, I would say that in a typical implementation they will be stored aspair<const K, V>
objects, i.e. exactly what the dereference operator evaluates to. Normally, the map does not need to modify the key portion of the pair after it is initialized, so it should not run into any problems with the fact that the first member of the pair is const-qualified.