C++ 悬空引用奇怪的行为

Gab*_* Re 3 c++ c++11 c++14 c++17

int*& f(int*& x, int* y){
 int** z = &y;
 *z = x;
 return *z;
}
Run Code Online (Sandbox Code Playgroud)

大家好,我在考试中得到了这段代码,但我遇到了一些问题。

我的理解是,给定对函数体中构造的指针 (x) 和指针副本 (y) 的引用,将创建本地双指针 (z) 并用 y 左值初始化,然后取消引用 1 次,因此 y 正在被访问,并且 y 中包含的地址现在变成 x 中包含的地址。之后 *z 作为指针引用返回,我假设为 y。

如果我之前的部分是正确的,我不会解释为什么返回在函数退出时被释放的 y (因为临时参数)不会在程序中产生任何问题,实际上考试答案是该函数返回一个悬空参考我同意这一点,但是,复制/粘贴代码,并“播放”返回的变量,甚至在返回参数后进行随机操作,以便“编辑堆栈”,其中释放的 y 仍然存在并且“准备被覆盖”(如果我仍然是对的)不会出现程序的任何未定义的行为。

我唯一的解释是,返回仅复制 y 中包含的右值,或者可能返回左值和右值(因为返回对指针的引用),但当与外部指针“调用”函数 y 关联时,它不会没有得到正确的释放,或者以某种方式获取值的指针取代了被释放的 y 指针。

在底部您可以找到用于测试函数 int*& f(int*&, int*) 的代码。

我的问题是:这是一个正确的悬空引用,还是可以在程序中使用这样的东西的边界情况?

#include <iostream>
using namespace std;
int a = 65;

int*& f(int*& x, int* y)
{
    cout<<"indirizzo di y: "<<&y<<endl;
    cout<<"indirizzo di x: "<<&x<<endl;

    int** z = &y;
    cout<<"indirizzo di *z prima: "<<*z<<endl;
    *z=x;
    cout<<"indirizzo di *z dopo: "<<*z<<endl;
    cout<<"y punta a: "<<y<<endl;
     cout<<"z dopo: "<<z<<endl;
    return *z;
}

int*& crashaFisso() //function that crashes every time with a "proper" dangling reference
{
    int a=10;
    int* x =&a;
    return x;
}

int main()
{
    system("CLS");
  
    int b = 20;
    int codicerandom=0;
    
    int* i = &a;
    cout<<"indirizzo di i: "<<i<<endl;
    int* u = &b;
    cout<<"indirizzo funzione: "<<&f(i,u)<<endl;
    int* aux = f(i,u);

    int* crash = crashaFisso();

    cout<<"crash: "<<*crash<<endl;
    cout<<"aux: "<<*aux<<endl;

    for(int i=0;i<100;i++)
        codicerandom +=i;
    
    for(int i=0;i<100;i++)
        codicerandom +=i;
    for(int ji=100;ji>0;ji--)
    {
        codicerandom +=ji;
        for(int x=100;x>0;x--)
        {
            codicerandom -= x*2;
        }
    }
    
    cout<<codicerandom<<endl;


    cout<<"crash: "<<*crash<<endl;
    cout<<"aux: "<<*aux<<endl;

    cout<<"crash: "<<*crash<<endl;
    cout<<"aux: "<<*aux<<endl;

    a=32;

    cout<<"aux: "<<*aux<<endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

fre*_*ish 8

考试答案是该函数返回一个悬空引用

正确的。

但是 (...) 不呈现程序的任何未定义行为。

是什么让你这么想的?未定义的行为并不意味着“程序无法正常工作”或“程序崩溃”。未定义的行为正如它所说的那样:行为不是由标准定义的。事实上,它可能“正确”工作(无论这意味着什么),标准并不禁止它。这就是为什么它如此危险。因为也许在你的测试中它工作正常,因为硬件、操作系统、特定编译器以及发生的一些其他假设。但问题是它不能保证正常工作。如果你改变机器、操作系统、编译器(甚至切换优化设置)、代码,甚至两天后编译它,它可能会表现得很奇怪,以一种(ekhm)未定义的方式。

一般来说,如果 UB 存在,则无法知道程序的行为是否正确。您试图通过思考左值、右值、分配等来分析情况,而现实情况是,当 UB 存在时,整个程序就没有意义了。你只是浪费时间。

不要写UB代码。不管它看起来是否有效。