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

时间:2019-07-18 06:15:06

标签: c++ iterator std

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

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

4 个答案:

答案 0 :(得分:5)

这里的问题并不那么明显。正如其他人已经建议的那样,您正在使用错误的算法,或者以错误的方式使用了算法。当您要使用迭代器并传递范围时,请使用以下方法:

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()和{{ 1}},因为vec.end()(未考虑中间值),但是由于函数调用后它们不再存在,因此使用它们(例如,取消引用它们)是UB(附加说明:理论上,您可以通过以下方法解决该问题) vec.begin() < vec.end(),它在不悬挂时取消对返回的Interator的引用,但这只是修复UB部分,而不是您想要的,即它仍然比较两个迭代器,而不是范围内的元素。 / p>

请注意,当您尝试使用int min_value = *std::minmax(vec.begin(), vec.end()).first;而不是std::list<int>编译此示例时,它将不会编译,因为std::vector迭代器不是随机访问且不能与std::list进行比较。

有时候,随机访问的力量似乎会让您陷入麻烦:)

答案 1 :(得分:3)

您无需取消引用对即可获取值。 std::minmax返回对最大值和最小值的引用,或者按值返回。

如果您打算让该元素具有迭代器,则必须使用std::minmax_element 代替。

修改

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

答案 2 :(得分:2)

您的程序崩溃是因为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返回一对对迭代器的引用,这些引用已被破坏。

在第[1]行中,begin / end按值返回迭代器,因此它们作为const T&的参数绑定到minmax上,但是当该行结束时它们的生命周期就结束[1]被执行。

答案 3 :(得分:1)

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

如果像传递std::minmax(vec.begin(),vec.end())那样传递两个迭代器,则minmax从头到尾进行迭代,但是它将比较迭代器{{1} }和begin();结果将是一对,其中两个元素之一包含迭代器end(),另一个包含迭代器vec.end()

因此,要获取值,实际上您必须取消引用vec.begin(),因为它包含迭代器。但是作为minmax.first或``minmax.second minmax.first vec.end()will contain vec.end()`,这是未定义的行为。

要获取范围内的最小/最大元素,请写...

, you actually dereference