尝试取消引用迭代器时出现段错误

Segfault when attempting to de-reference iterator

我正在尝试从向量中获取 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;

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

您无需取消引用该对即可获取值。 std::minmax returns 对最小值和最大值的引用或 returns 按值。

如果你想获取元素的迭代器,那么你必须使用 std::minmax_element 相反。

编辑

您在代码中所做的是查找两个迭代器的最小值和最大值,然后您需要取消引用以获取值。 live

您的程序崩溃,因为 minmax 通过调用 begin/end 获取迭代器,并且当完整表达式结束时这些迭代器被销毁:

auto minmax = std::minmax(vec.begin(), vec.end()); // pass iterators as temporary [1]
int min_value = *minmax.first; // here, you have dangling references to iterators

minmax returns 对迭代器的引用,已被销毁。

行 [1] begin/end returns 迭代器按值,因此它们作为 minmax 的参数绑定到 const T& 但它们执行第 [1] 行时生命周期结束。

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

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 <进行比较。指向序列开头的随机访问迭代器将始终与指向结尾的迭代器进行比较,因此您返回的最小值实际上是一对 constvec.begin() 和 [= 的引用18=] 因为 vec.begin() < vec.end() (没有考虑中间值),但是因为它们在函数调用后不再存在,所以使用它们(例如取消引用它们)是 UB(补充说明:理论上你可以解决这个问题int min_value = *std::minmax(vec.begin(), vec.end()).first;,它取消引用返回的交互器,但它不是悬挂的,但这只是修复了 UB 部分,而不是你想要的,即它仍然比较两个迭代器,而不是范围内的元素)。

请注意,当您尝试使用 std::list<int> 而不是 std::vector 编译此示例时,它不会编译,因为 std::list 迭代器不是随机访问的,并且不能'无法与 operator <.

进行比较

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

您可能错误地解释了 std::minmax 的含义:std::minmax 要么采用 两个参数 (导致仅比较这两个参数),要么 一个参数 initializer_list 类型(搜索 min max 然后在其中)。

如果你传递两个迭代器,就像你对std::minmax(vec.begin(),vec.end())所做的那样,那么minmax不会从头到尾迭代,但它会比较迭代器 begin()end();结果将是一对,其中两个元素之一包含迭代器 vec.end(),另一个包含迭代器 vec.begin().

因此,为了获取值,您实际上必须取消引用 minmax.first,因为它包含一个迭代器。但是作为 minmax.first 或 ``minmax.secondwill containvec.end(), you actually dereferencevec.end()`,这是未定义的行为。

要获得范围内的 smallest/largest 元素,写...

int smallest_element = *min_element(vec.begin(),vec.end());