【发布时间】:2012-05-22 00:57:14
【问题描述】:
我对@987654325@ 的语义有点困惑。我的意思是,我没有抱怨 - 标准就是标准,API 就是它的样子。不过,
插入操作检查每个插入的元素是否 另一个元素已经存在于容器中,具有相同的键 值,如果是,则不插入元素并且其映射值不 以任何方式改变。
而且 - 只有在其单参数版本pair<iterator,bool> insert ( const value_type& x ); 中,它才会告诉您它是否甚至将(新的,可能不同的)值插入到键中。据我了解,如果键已经存在,迭代器版本会默默地忽略插入。
对我来说,这简直是违反直觉的,我本来希望在插入时会覆盖值部分并丢弃旧值部分。显然,STL 的设计者有不同的想法——任何人都知道(历史)基本原理,或者可以对现有语义如何(更)有意义给出彻底的解释?
举例:
在std::map等单键映射中实现插入有几种基本方法:
- 插入,如果已经存在则替换
- 插入,如果已经存在则忽略(这是 std::map 的行为)
- 插入,如果已经存在则抛出错误
- 插入,如果已经存在 UB
我现在正试图理解为什么insert_or_ignore 比insert_or_replace(或insert_or_error)更有意义!
我查看了我的TC++PL 副本(不幸的是我只有德语版),有趣的是,Stroustrup 在第 17.4.1.7 章(map 的列表操作)中写道:(抱歉粗略的翻译来自德语)
(...) 通常情况下,一个键(原文如此!)是否是新的并不重要 在调用
insert()之前插入或已经存在 (...)
在我看来,这仅适用于 set,而不适用于 map,因为对于地图,如果提供值已插入或旧值保留在地图中。 (这显然与密钥无关,因为它是等效的。)
注意:我知道operator[],我知道Effective STL 的第24 项以及那里提出的efficientAddOrUpdate 函数。我只是想知道insert 语义的基本原理,因为我个人觉得它们违反直觉。
【问题讨论】:
-
好吧,您没有要求它修改现有值,而是要求它插入一个(新)值。我同意更一致地报告失败将是一件好事。您仍然可以取消引用返回的迭代器并检查是否存在新值或旧值,甚至可以使用该迭代器来更新现有值。
-
如果要替换/创建,请使用
operator[]。 -
这里有一些代码可以将"insert forcefully" 转换为地图。
-
@KerrekSB:为什么不简单地使用惯用的
operator[]? -
@MatthieuM.:如果您需要根据值是否已经存在做出一些额外的决定和/或记录怎么办?
标签: c++ map standard-library