为啥 std::distance 在 stl 地图中被击中?

Posted

技术标签:

【中文标题】为啥 std::distance 在 stl 地图中被击中?【英文标题】:why std::distance struck in a stl map?为什么 std::distance 在 stl 地图中被击中? 【发布时间】:2021-06-24 06:38:59 【问题描述】:

我想使用 std::distance 来查找我的元素的索引。

代码如下:

#include <iostream>
#include <map>
#include <iterator>
#include <string>
using namespace std;

int main() 
  std::map<int, std::string> m = 1, "huang", 2, "wei", 3, "pu";
  auto it = m.find(2);
  cout << std::distance(it, m.begin()) << endl; // struck here
  cout << std::distance(it, m.end()) << endl;

但我发现代码在cout 中被击中,我的代码有什么问题?

【问题讨论】:

应该是std::distance(m.begin(), it) 如果 last 不能通过(可能重复)从 first 递增 first 到达,则行为未定义。 distance ref 如果编译器没有推断出行为未定义,而是代码尝试递增it,直到达到m.begin(),这将需要很长时间。或者这需要很短的时间,但风扇可能会加速。 【参考方案1】:

问题在于std::distance(first, last)...

返回从第一个到最后一个的跃点数 - cppreference.com

所以你需要改成这样:

// ...   
std::distance(m.begin(), it); // the number of hops from m.begin() to it
// ...

注意,通过这种方式,我们为distance 提供了一个有效的迭代器范围。对构成迭代器范围的迭代器有要求:

它们必须引用 同一个容器 可以通过重复增加begin 来达到end。在 换句话说,end 不能在 begin 之前。

在您的案例中违反了第二个要求。

【讨论】:

【参考方案2】:

std::map的迭代器不是随机访问的,那么对于std::distance()

如果 InputIt 不是 LegacyRandomAccessIterator,则如果 last 不能通过(可能重复)先递增从第一个到达,则行为未定义。

所以std::distance(it, m.begin()) 的行为是未定义的,m.begin()(指向第一个元素)不能通过递增it(指向第二个元素)来达到。你应该改用std::distance(m.begin(), it)

【讨论】:

以上是关于为啥 std::distance 在 stl 地图中被击中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在地图stl中搜索时差很大?

std::distance 很慢,如何改进? [关闭]

在std :: list中,std :: distance(it.begin(),std :: prev(it.end())是否等于list.size()? [重复]

`std::partition()` 的时间复杂度

所有地图变体的通用打印功能 C++ STL

将地图值复制到 STL 中的向量