map::iterator 会产生左值吗?

发布于 2024-09-24 07:51:17 字数 556 浏览 1 评论 0原文

换句话说,当 imap::iterator 时,以下内容是否提供预期的语义(即它修改映射)

*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 a pair<K,V> somewhere,
  • Or there is some clever proxy class which map<K,V>::iterator::operator* returns. In this case, how is operator-> implemented ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

镜花水月 2024-10-01 07:51:17

我试图通过标准来追踪这一点:

  • 对于 mapvalue_typepair per 23.3.1/2

  • map 类支持双向迭代器,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> the value_type is pair<const Key,T> per 23.3.1/2

  • The 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 with value_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.

简美 2024-10-01 07:51:17

地图几乎就像一组对。是的,它的迭代器可能被实现为一个指向带有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 type pair<const K, V> so you can't assign to first.

*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 overloading operator ->.

或十年 2024-10-01 07:51:17

首先,从技术上讲,在这种情况下,一元 * 运算符的计算结果为左值。然而,C 语言中的术语“左值”基本上表示在存储(内存)中具有位置(地址)的内容。在 C++ 术语中,甚至函数也是左值。因此,同样,在上面的示例中,一元 * 产生一个左值。如果您愿意,您可以获取该左值的地址,即您可以计算 &*i&i->first&i->second (假设内置一元 &)。

其次,由于您最初的示例涉及赋值,因此您实际上必须谈论可修改的左值。您会看到,左值属性本身与可赋值关系不大。要使用内置赋值运算符,您需要一个可修改的左值。从解除引用的迭代器中得到的是 std::mapvalue_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 of std::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 as pair<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.

稀香 2024-10-01 07:51:17
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
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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文