尝试取消引用迭代器时出现段错误
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 <
进行比较。指向序列开头的随机访问迭代器将始终与指向结尾的迭代器进行比较,因此您返回的最小值实际上是一对 const
对 vec.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 contain
vec.end(), you actually dereference
vec.end()`,这是未定义的行为。
要获得范围内的 smallest/largest 元素,写...
int smallest_element = *min_element(vec.begin(),vec.end());
我正在尝试从向量中获取 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 <
进行比较。指向序列开头的随机访问迭代器将始终与指向结尾的迭代器进行比较,因此您返回的最小值实际上是一对 const
对 vec.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 contain
vec.end(), you actually dereference
vec.end()`,这是未定义的行为。
要获得范围内的 smallest/largest 元素,写...
int smallest_element = *min_element(vec.begin(),vec.end());