【问题标题】:How do I know if std::map insert succeeded or failed?我如何知道 std::map 插入是成功还是失败?
【发布时间】:2011-02-24 14:46:38
【问题描述】:

我在多线程应用程序中有一个映射,将一个名为 uuid 的类映射到指针。 我想知道插入操作是否成功失败。

例如

_mymap.insert(hint, MyMap::value_type(entry.uuid, itemptr));

如果失败会抛出异常还是什么?

【问题讨论】:

  • @Armen,试过了。我找不到任何显示它的例子。所有示例都假设插入成功。

标签: c++ linux gcc stl


【解决方案1】:

实际上,带有提示参数的插入方法不会返回插入是否成功。检查插入是否实际发生的一种方法是在插入前后检查地图的大小。如果相同,则插入失败(即密钥已经存在)。我知道这听起来很难看,但这是我能想到的最有效的方法。事实上,我认为没有令人信服的理由表明带有提示的插入不应该像常规的非提示插入那样返回一对(包括布尔值)。但一旦在旧标准中指定,就很难更改,因为这是一个重大更改,C++ 社区对此大多不满。

原始(错误)答案

See this link

... 返回一个对,其成员 pair::first 设置为一个迭代器,该迭代器指向新插入的元素或映射中已经具有相同值的元素。如果插入了新元素,则该对中的 pair::second 元素设置为 true,如果存在具有相同值的元素,则设置为 false。

该链接还包含一个示例

例如:

if(mp.insert(make_pair(key, value)).second == false)
{
   cout << "Insertion failed. Key was present"
}

【讨论】:

  • 其实这是不正确的。带有提示参数的 insert() 方法不返回一对,而只是一个迭代器。
  • 重要提示:如果您只是插入元素 WITHOUT 提示参数,请使用 See this link 中的答案.最初的答案是错误的,因为它是针对我们不需要提示参数但问题的发布者需要提示的情况。如果我们不需要提示,最初的答案是NOT错误,这通常是这种情况。
  • 关于 insert 的提示版本返回 iterator 而不是 pair 的原因,Nicolai M. Josuttis 在他的“C++ 标准库”(第一和第二版)中第二个版本),通过这样说你有一个insert函数,它对所有容器类型具有相同的接口在STL中定义(vectordequelistsetmultisetmapmultimap)。
  • 根据您对失败的定义,您可能需要 insert_or_assign(c++17 标准),其返回的布尔值(如果使用不带提示的版本)区分插入大小写 (true) 和赋值情况(假)。见reference
【解决方案2】:
typedef std::map<std::string, int> map;
map m;
std::pair<map::iterator,bool> result = m.insert(std::make_pair("hi", 42));

result.second 包含你想要的内容

【讨论】:

    【解决方案3】:

    第一个插入成员函数 返回一对其 bool 组件 如果进行了插入,则返回 true 如果地图已经包含,则为 false 其键具有等价的元素 排序中的值,并且其 迭代器组件返回地址 插入新元素的位置或 元素所在的位置。

    访问一个迭代器组件 该成员返回的对 pr 函数,使用 pr.first,并 取消引用它,使用 *(pr.first)。到 访问一对 pr 的 bool 组件 此成员函数返回,使用 pr.second.

    第二个插入成员函数, 提示版本,返回一个迭代器 指向新的位置 元素已插入到地图中。

    来源:http://msdn.microsoft.com/en-us/library/81ac0zkz(v=vs.80).aspx

    【讨论】:

    • 好吧,这很难理解。你可以给我一个例子吗。 MS 实际上没有我能看到的。
    • 我认为您的链接错误。它指向标题为“System.Collections.Generic Namespace”的页面。
    • 是的,我想指出我在 linux 下使用 gcc。希望所有的 STL 都是平等的吗?
    • @Matt H:是的,STL 是标准化的。
    【解决方案4】:

    这取决于你所说的失败或成功。

    std::map::insert 在插入新元素时成功,否则返回一个指向已存在元素的迭代器。

    如果没有足够的内存来插入新元素,std::map::insert 将失败并抛出 std::bad_alloc

    【讨论】:

      【解决方案5】:

      是的,它会抛出 STL 中使用的异常之一,例如当内存不足时。这是失败的情况。

      或者您是否也想知道该元素是否已包含在实例中?

      【讨论】:

        【解决方案6】:

        在插入提示后,还可以知道在地图中是否插入或找到了一对(更快)。

        使用提示方法插入另一对相同的第一对,以及您确定不在地图中的第二对(如 -1 表示正第二个整数的地图)。如果返回的迭代器有这个不可能的值,它是新插入的,如果不是,它是在map中找到的。然后可以更改返回的迭代器。 示例:在 map m ((0, 1), (2, 3), (4, 5)) 中插入对 p (2,4) 和 p (6, 5)。

        int main (int argc, char* argv []) {
          std::pair<int, int> tmp [3] = {
            std::pair<int, int> (0, 1),
            std::pair<int, int> (2, 3),
            std::pair<int, int> (4, 5)
          };
          std::map<int, int> m ((std::pair<int, int>*) tmp, (std::pair<int, int>*) &tmp [3]);
        
          std::cout << "initial map == ";
          std::for_each (m.begin (), m.end (), [] (const std::pair<int, int>& p) {
            std::cout << p.first << "->" << p.second << "   ";
          });
          std::cout << std::endl;
          std::cout << std::endl;
        
          {
            //insertion of a pair of first already in map
            std::cout << "insertion of pair 1 == std::pair<int, int> (2, 4) from second iterator" << std::endl;
            std::map<int, int>::iterator ihint (m.begin ()), k (ihint); ++ihint;
            std::pair<int, int> pfoo (2, -1);
            k = m.insert (ihint, pfoo);
            if (k->second == -1) {
              std::cout << "\tthe pair was inserted" << std::endl;
              k->second = 4;
            }
            else {
              std::cout << "\ta pair with such a first was in the map" << std::endl;
            }
          }
          std::cout << "m after insertion of pair 1 == ";
          std::for_each (m.begin (), m.end (), [] (const std::pair<int, int>& p) {
            std::cout << p.first << "->" << p.second << "   ";
          });
          std::cout << std::endl;
          std::cout << std::endl;
        
          {
            //insertion of a pair of first not in map
            std::cout << "insertion of pair 2 == std::pair<int, int> (6, 5) from third iterator" << std::endl;
            std::map<int, int>::iterator ihint (m.begin ()), k (ihint); ++ihint; ++ihint;
            std::pair<int, int> pfoo (6, -1);
            k = m.insert (ihint, pfoo);
            if (k->second == -1) {
              std::cout << "\tthe pair was inserted" << std::endl;
              k->second = 5;
            }
            else {
              std::cout << "\ta pair with such a first in the map" << std::endl;
            }
          }
          std::cout << "m after insertion of pair 2 == ";
          std::for_each (m.begin (), m.end (), [] (const std::pair<int, int>& p) {
            std::cout << p.first << "->" << p.second << "   ";
          });
          std::cout << std::endl;
        }
        

        输出: 初始映射 == 0->1 2->3 4->5

        从第二个迭代器插入对 1 == std::pair (2, 4)

        地图上有一对这样的第一对

        插入对后的m == 0->1 2->3 4->5

        从第三个迭代器插入对 2 == std::pair (6, 5)

        这对已插入

        插入pair后的m == 0->1 2->3 4->5 6->5

        【讨论】:

        • 由于我的答案被否决且没有任何解释,我添加了初始地图构造,插入了两对(一对在地图中,一对不在)并打印提示插入结果。使用前增量,比后增量更快。我正在使用的地图不再称为“map”,而是“m”,所以它不会混淆人们“使用命名空间 std”,而只是“m”。 foo 迭代器的修改只是在插入的情况下执行
        • 我没有对你投反对票,但你的答案肯定不容易阅读(我说的是文本,而不是代码)。
        • 我的示例解释了如何使用带有提示的插入来判断一对是在地图中插入还是检索到
        猜你喜欢
        • 2020-03-01
        • 2019-01-14
        • 1970-01-01
        • 1970-01-01
        • 2015-10-02
        • 1970-01-01
        • 2015-05-30
        • 2010-12-12
        相关资源
        最近更新 更多