unordered_map :: find()和两个迭代器

时间:2014-11-13 12:18:33

标签: class c++11 iterator return-value unordered-map

拥有私人会员的课程

std::unordered_map<std::string, size_t> myMap;

和相应的getter

std::unordered_map<std::string, size_t> getMyMap() const {return myMap;}

我通过两次应用std :: unordered_map :: find()来观察奇怪的行为,每次都保存返回的迭代器,例如

auto pos1 = test.getMyMap().find("a");
auto pos2 = test.getMyMap().find("a");

Altough我寻找相同的钥匙&#34; a&#34;迭代器指向不同的元素。以下示例代码说明了问题:

#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>

class MyMap{
 public:
  MyMap(){
    myMap= {
      {"a", 1},
      {"b", 2}
    };
  }

  std::unordered_map<std::string, size_t> getMyMap() const {return myMap;}

private:
  std::unordered_map<std::string, size_t> myMap;
};

int main(){

  MyMap test;

  auto pos1 = test.getMyMap().find("a");
  auto pos2 = test.getMyMap().find("a");
  std::cout << pos1->first << "\t" << pos1->second << std::endl;
  std::cout << pos2->first << "\t" << pos2->second << std::endl;
}

使用g ++ -std = c ++ 11进行编译并运行

b   2
a   1

第一行意外。它应该是&#34; 1&#34;。

将代码更改为

  auto pos3 = test.getMyMap().find("a");
  std::cout << pos3->first << "\t" << pos3->second << std::endl;
  auto pos4 = test.getMyMap().find("a");
  std::cout << pos4->first << "\t" << pos4->second << std::endl;

产生正确的输出

a   1
a   1

此外,只需在主文件中创建unordered_map并应用find()即可。似乎问题与getter方法有关,可能与返回值优化有关。你对这种现象有什么解释吗?

2 个答案:

答案 0 :(得分:0)

这是因为您的代码中有undefined behaviorgetMyMap会返回地图的副本,这是在表达式test.getMyMap().find("a")完成后会被破坏的副本。

这意味着您有两个指向不再存在的映射的迭代器。

解决方案非常简单:让getMyMap返回一个常量引用:

std::unordered_map<std::string, size_t> const& getMyMap() const;

它似乎适用于后一种情况,因为它是未定义行为的陷阱,它可能有时似乎就像它起作用,而实际上它并没有。

答案 1 :(得分:0)

test.getMyMap().find("a");对原始find的副本执行myMap,该副本在表达式完成后被破坏,使迭代器pos1pos2变为非现有地图,调用未定义的行为

相反,您可以播放,如下所示:

  auto mymap = test.getMyMap() ;   // Store a copy

  auto pos1 = mymap.find("a");    // Then do stuff on copy
  auto pos2 = mymap.find("a");