首页 > 解决方案 > 尝试取消引用迭代器时出现段错误

问题描述

我正在尝试从向量中获取 minmax 元素。下面是我的代码的一个过于简化的片段:

std::vector<int> vec;
for (int i = 1; i < 10; i++) {
  vec.push_back(i);
}
auto minmax = std::minmax(vec.begin(), vec.end());
int min_value = *minmax.first;

当我尝试在最后一条语句中取消引用迭代器时,出现段错误。我不明白为什么。

标签: c++iteratorstd

解决方案


这里的问题并不像它可能的那样明显。正如其他人已经建议的那样,您使用了错误的算法,或者以错误的方式使用了算法。当你想使用迭代器并传入一个范围时,使用这个:

auto minmax = std::minmax_element(vec.cbegin(), vec.cend());
int min_value = *minmax.first;

如果您想使用std::minmax,则需要传递两个要比较的类型的参数,或者传递一个std::initializer_list

auto minmax1 = std::minmax_element(42, 43);
auto minmax2 = std::minmax_element({42, 43, 50, 49, 40});

int min_value = minmax1.first;

在第二个示例中,返回的不是迭代器,而是const限定引用或值(当传递了初始化列表时)。

你为什么犯这个错误?事实证明,将迭代器传递给std::minmax愉快地编译,因为std::minmax它是一个函数模板,可以比较你给它的任何类型。在这种情况下,vec.begin()vec.end()是随机访问迭代器,它们可以通过 进行比较operator <。序列开头的随机访问迭代器将始终与指向结尾的迭代器进行比较,因此您返回的最小值实际上是对和的一对const引用vec.begin()vec.end()因为vec.begin() < vec.end()(没有考虑中间值),但是因为它们在函数调用后不再存在,使用它们(例如取消引用它们)是 UB(附加说明:理论上你可以通过int min_value = *std::minmax(vec.begin(), vec.end()).first;,它在返回的迭代器没有悬空时取消引用,但这只是修复了 UB 部分,而不是你想要的,即它仍然比较两个迭代器,而不是范围内的元素)。

请注意,当您尝试使用 astd::list<int>而不是 a来编译此示例时std::vector,它将无法编译,因为std::list迭代器不是随机访问且无法通过 比较operator <

有时,随机访问的力量似乎会给你带来麻烦:)


推荐阅读