【问题标题】:Segfault when attempting to de-reference iterator尝试取消引用迭代器时出现段错误
【发布时间】:2019-07-18 06:15:06
【问题描述】:

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

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;

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

【问题讨论】:

  • 您确定要取消引用它吗?我会仔细检查the documentation。您可能会将其与 std::mixmax_element 混淆。
  • 基本上,您试图在某个内存位置地址获取和 int 值,并且作为地址,您使用向量中的最小值......这对我来说听起来很奇怪。
  • 你知道这是寻找两个 iterators 中最小和最大的吗? IE。不是他们指向的价值观?
  • 避免使用auto的另一个原因

标签: c++ iterator std


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

请注意,当您尝试使用std::list&lt;int&gt; 而不是std::vector 编译此示例时,它不会编译,因为std::list 迭代器不是随机访问且无法与operator &lt; 进行比较。

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

【讨论】:

    【解决方案2】:

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

    如果你想获得一个元素的迭代器,那么你必须使用std::minmax_element 而是。

    编辑

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

    【讨论】:

      【解决方案3】:

      您的程序崩溃是因为 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 按值返回迭代器,因此它们作为 minmax 的参数绑定到 const T&amp;,但它们的生命周期在第 [1] 行执行时结束。

      【讨论】:

        【解决方案4】:

        您可能错误地解释了 std::minmax 的含义:std::minmax 要么采用 两个参数(导致只比较这两个),要么采用 @ 类型的 一个参数 987654323@(然后在其中搜索 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()`,这是未定义的行为。

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

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

        【讨论】:

          猜你喜欢
          • 2014-02-03
          • 2015-08-07
          • 1970-01-01
          • 1970-01-01
          • 2021-10-04
          • 1970-01-01
          • 2013-11-10
          • 1970-01-01
          相关资源
          最近更新 更多