当C ++将元素从函数的返回值存储到std :: vector时出现意外的结果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当C ++将元素从函数的返回值存储到std :: vector时出现意外的结果相关的知识,希望对你有一定的参考价值。

当函数涉及重新分配时,我发现一些编译器可能在函数调用之前保存地址。它导致存储在无效地址中的返回值。

在上面的描述中有一个例子来解释行为。

#include <stdio.h>
#include <vector> 
using namespace std;

vector<int> A; 
int func() { 
    A.push_back(3);
    A.push_back(4);
    return 5; 
} 
int main() { 
    A.reserve(2);
    A.push_back(0);
    A.push_back(1);
    A[1] = func();
    printf("%d
", A[1]);
    return 0;
}

有一些常见的C ++编译器,测试结果如下。

  • GCC(GNU编译器集合):运行时错误或输出1
  • Clang:输出5
  • VC ++:输出5

是不确定的行为?

答案

在C ++ 17之前的所有C ++版本中,行为都是未定义的。原因很简单,可以按任何顺序评估赋值运算符的两边:

  • 假设首先评估A[1],你得到一个int&指的是那时A的第二个元素。
  • 然后,评估func(),它可以重新分配矢量的存储空间,使先前检索的int&成为悬空参考。
  • 最后,执行赋值,写入未分配的存储。由于标准分配器缓存内存,操作系统通常不会捕获此错误。

仅在C ++ 17中,用于赋值的special rule 20

在每个简单赋值表达式E1 = E2和每个复合赋值表达式E1 @ = E2中,E2的每个值计算和副作用在E1的每个值计算和副作用之前被排序。

使用C ++ 17时,必须在调用A[1]之后评估func(),然后documentation提供定义的可靠行为。

另一答案

如果你检查push_back(),在“Iterator Invalidation”下,你会看到std::vector可能会使每个迭代器无效,如果它改变了容量,因为它必须重新分配内存。请记住,对于push_back(),指针也是有效的迭代器。因为qazxswpoi可能会或可能不会重新分配,并且您无法知道它是否会发生,因此行为未定义。

以上是关于当C ++将元素从函数的返回值存储到std :: vector时出现意外的结果的主要内容,如果未能解决你的问题,请参考以下文章

C++_第七章函数的基本知识_求阶乘的子函数_ 函数参数类型为数组_ 求数组内所有元素和部分元素和的方法_实现了先从键盘输入到一个数组中,再用for循环取读出数组中的元素 for循环也可以用bre(

C语言中,数组名作为函数参数,属于啥传递,为啥?

嵌入式体系结构复习笔记

Python:返回特定范围内的矩阵值,范围以元组形式给出(从,到)

Matlab当中size() length()等函数讲解

存储过程和存储函数区别