【问题标题】:Does map store elements as std::pair?map 是否将元素存储为 std::pair?
【发布时间】:2020-08-27 06:19:19
【问题描述】:

std::map 是否将元素存储为std::pair?遍历 map 如下所示:

#include <map>
int main() {
    std::map<int, char> m;
    m[1] = 'A';
    m[2] = 'B';
    m[3] = 'C';

    std::map<int, char>::iterator it;
    for(it = m.begin(); it != m.end(); it++)
    {
       std::cout << "Key: "    << it->first;
       std::cout << " Value: " << it->second;
       std::cout << std::endl;
    } 
}

【问题讨论】:

  • 为什么不只看你的特定编译器的实现。并非所有供应商都使用相同的模板。模板的源代码通常在头文件中。
  • 来自en.cppreference.com/w/cpp/container/map:“std::map 是一个排序的关联容器,其中包含具有唯一键的键值对。”。实际上,我会说:是的。从技术意义上说:不, std::map 实现只是提供了这样的迭代器(但我不是专家)。我不确定你在找什么?

标签: c++ stdmap std-pair internals


【解决方案1】:

不,std::map 不会将数据存储成对,它只是将数据公开成对。虽然不禁止使用std::pair 在底层存储中。

在典型的红黑树实现中,除了存储的键和值之外,您至少需要两个指向子节点的指针(可能还有一个指向父节点的指针,我真的不记得 RB 树是如何工作的,抱歉)。底层存储类型是 std::map::node_type(自 C++17 起添加),在标准中未指定(也称为特定于实现)。


注意有这个子句(来自cppreference):

对于 key_type 为 K 且 mapped_type 为 T 的所有 map 容器(std::map、std::multimap、std::unordered_map 和 std::unordered_multimap),如果用户操作涉及节点句柄的行为未定义为std::pair&lt;K, T&gt;std::pair&lt;const K, T&gt; 存在-定义的std::pair 特化。

这表明标准绝对允许将 node-handle 类型的数据存储为std::pair(并且实现可能假设std::pair 的行为完全符合预期)。

【讨论】:

  • 这里说元素的类型是std::map是std::pair:stackoverflow.com/a/15451409/7101138。那么这不正确吗?
  • @michalt38 对于几乎所有用途,std::map 存储std::pair 类型对象的近似值已经足够了。您始终以std::pair 插入和读取数据。在实践中,数据存储在节点中,其中包含std::pair(或者只是键和值)和一些指针。
  • 但是我们可以说std::map中的元素类型是std::pair吗?
  • @michalt38 是的,std::map 中的元素类型将是 std::pair(并且这些元素在内部存储在未指定的节点类中)。
  • @user1687327 这是可能的,但 gcc 例如stores std::pair&lt;const K, T&gt; in map's node_type。我想一个实现可以通过存储std::pair&lt;K, T&gt; 并在每次返回时强制转换它(可能以一些涉及UB的方式),但我想不出使用它比std::pair&lt;const K, T&gt; 有什么好处。 .
【解决方案2】:

简单的答案是肯定的。

[map.overview]map 有一个value_type

using value_type = pair<const Key, T>;

[unord.map.overview] 也有相同的value_type


编辑:正如 Yksisarviven 所说,这些仍然需要存储在某种 node_type 中,这在 C++17 标准中未指定

【讨论】:

    【解决方案3】:

    std::map::extract 我会得出结论,它将它存储为std::map::node_type。这在实践中可能是特定于实现的。研究我的 GCC 9.3 实现结果:

      template<typename _Val>
        struct _Rb_tree_node : public _Rb_tree_node_base
        {
          typedef _Rb_tree_node<_Val>* _Link_type;
    
    #if __cplusplus < 201103L
          _Val _M_value_field;
    
          _Val*
          _M_valptr()
          { return std::__addressof(_M_value_field); }
    
          const _Val*
          _M_valptr() const
          { return std::__addressof(_M_value_field); }
    #else
          __gnu_cxx::__aligned_membuf<_Val> _M_storage;
    
          _Val*
          _M_valptr()
          { return _M_storage._M_ptr(); }
    
          const _Val*
          _M_valptr() const
          { return _M_storage._M_ptr(); }
    #endif
        };
    

    这意味着在我的实现中,节点中包含一个 _Val = std::pair,即是的,它存储 std::pair,但包装在一个节点中。

    【讨论】:

      猜你喜欢
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多