当前位置: 首页 > 知识库问答 >
问题:

C++11中unordered_map会破坏它所插入的内容,这是C++标准委员会的意图吗?

洪国兴
2023-03-14
#include <memory>
#include <unordered_map>
#include <iostream>

int main(void)
{
  std::unordered_map<int, std::shared_ptr<int>> map;
  auto a(std::make_pair(5, std::make_shared<int>(5)));
  std::cout << "a.second is " << a.second.get() << std::endl;
  map.insert(a); // Note we are NOT doing insert(std::move(a))
  std::cout << "a.second is now " << a.second.get() << std::endl;
  return 0;
}
a.second is 0x8c14048
a.second is now 0x8c14048
a.second is 0xe03088
a.second is now 0
template <class P> pair<iterator,bool> insert ( P&& val );

答案就在眼前:unordered_map::value_type是一对 ,编译器会正确地认为一对 是不可转换的。因此,编译器选择move universal reference重载,尽管程序员没有使用std::move(),但它会破坏原来的引用,因为std::move()是表示可以破坏变量的典型惯例。因此,根据C++11标准,插入破坏行为实际上是正确的,而旧的编译器是不正确的。

你现在大概可以明白为什么我花了三天时间来诊断这个bug了。在大的代码库中,插入到unordered_map中的类型是一个用源代码术语定义的typedef,这一点并不明显,而且从来没有人想过检查typedef是否与value_type相同。

所以我的问题堆栈溢出:

C++标准委员会有意这样做吗?

您建议如何修改unordered_map::insert()以提供更好的行为?我这样问是因为如果这里有支持,我打算将这一行为作为一个N注提交给WG21,并要求他们实施一个更好的行为。

共有1个答案

钱和安
2023-03-14

正如其他人在评论中指出的那样,事实上,“通用”构造函数并不总是从它的论点出发。如果参数真的是rvalue,它应该移动,如果参数是lvalue,它应该复制。

您观察到的总是移动的行为是libstdc++中的一个bug,现在根据问题的注释已经修复。对于那些好奇的人,我看了一下g++-4.8头文件。

bits/stl_map.h,第598-603行

  template<typename _Pair, typename = typename
           std::enable_if<std::is_constructible<value_type,
                                                _Pair&&>::value>::type>
    std::pair<iterator, bool>
    insert(_Pair&& __x)
    { return _M_t._M_insert_unique(std::forward<_Pair>(__x)); }
  template<typename _Pair, typename = typename
           std::enable_if<std::is_constructible<value_type,
                                                _Pair&&>::value>::type>
    std::pair<iterator, bool>
    insert(_Pair&& __x)
    { return _M_h.insert(std::move(__x)); }
 类似资料:
  • ISO标准委员会,SC22 WG21,是在ISO规则下运行的。奇怪的是,这些规则并非标准化的,而是随着时间的变化而变化。(译注:标准委员会的规则并不标准) 大多数国家都有活跃的C++团体并形成了自己的国家标准。这些团体举行会议,通过网络协调一致,并向ISO会议推选代表。加拿大,法国,德国,瑞士,英国和美国是出席这些会议较多的国家。丹麦,荷兰,日本,挪威,西班牙和别的一些国家则是出席人数比较少的国家

  • 标准委员会包括大约200个人,其中有大约60位会出席每年两到三次一周时间的会议。除此之外,在一些国家还有一些国家标准组织和会议。多数成员通过出席会议,邮件讨论或提交论文供标准委员会斟酌等方式贡献自己的力量。多数成员有朋友或同事提供帮助。第一天,标准委员会召集从各个国家而来的代表,并且每一次会议由6到12个国家的代表参加。最终投票由20个国家标准组织完成。这样,ISO C++标准是一个集合了众人集体

  • 自然,涉及不同标准化的不同组织或个人都会有某些不同的目的,尤其是在细节和优先级方面。此外,详细的目标总是随时间的改变而变动的。请记住,委员会做不到认同每个人的意见本身也是件好事——志愿者们的资源还是非常有限的。然而,这里已经有一套在实际探讨中使用着的规范,以此来确定那种特性或是库文件可适当的用C++0x中: 保持稳定和兼容性——不要打破旧代码,而如果你非打破不可的话,不要静静的做(注:应该是让做点

  • 这个问题与现有的问题“使用C11的‘自动’能提高性能吗?” 这个问题的一个答案表明,使用不仅会有积极的影响,也会有消极的影响。 我认为我们需要一个单独的问题,答案集中在自动的那一面。

  • 我本来也是希望看到更多的标准库文件的。然而,(我改观是因为我)注意到标准库文件中定义的篇幅就占了超过75%的规范性文字(而且这些还不包括作为参考文献的C标准库文件)。虽然我们中的许多人也很希望看到更多的标准库文件,但是没人责备库工作组的懈怠。值得一提的是,C++98标准库已通过新语言特性的应用,如初始化列表 ,右值引用 ,可变参数模板 和constexpr(常量表达式) 而取得了显著改善。相比C+

  • 前往the papers section of the committee’s website 。那里有相当多的细节说明。寻找 “issues lists” 或 “state of” 列表(如 , State of Evolution (July 2008) )。主要的分组有: Core ( CWG )——处理语言技术事件并公式化 Evolution ( EWG )——处理与语言功能建议及横跨语言