int*& f(int*& x, int* y){
int** z = &y;
*z = x;
return *z;
}
Hello everyone, I've been given this code on an exam and I had some problems with it.
My understanding is that given a reference to a pointer (x) and a pointer copy constructed (y) in the body of the function a local double pointer (z) is being created and initialized with y l-value, then dereferenced 1 time, so y is being accessed and the address contained in y now becomes the address contained in x. Afterwards *z is returned as a pointer reference I assume of y.
If my previous part is correct I'm not explaining why returning y who gets deallocated on the exit of the function (since a temporary parameter) does not create any problems in the program, indeed the exam answer was that the function was returning a dangling reference and I agree with that, but, copy/pasting the code, and "playing" with the returned variable, even doing random stuff after the parameter is returned in order to "edit the stack" where the deallocated y still is present and "ready to be overwritten"(if I'm still right) does not present any undefined behaviour of the program.
My only explanation is that the return only copies the r-value contained in y or maybe it returns l-value and r-value (since returns a reference to a pointer) but when associated to an external pointer "calling" the function y doesn't get properly deallocated or in some way the pointer that gets the value takes the place of the y pointer that gets deallocated.
On the bottom you can find the code used to test the function int*& f(int*&, int*).
My question is: Is this a proper dangling reference or is a borderline case where such a thing could be used in a program?
#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;
}
the exam answer was that the function was returning a dangling reference
Correct.
but (...) does not present any undefined behaviour of the program.
What makes you think so? Undefined behaviour doesn't mean "program doesn't work correctly" or "program crashes". Undefined behaviour means exactly what it says: the behaviour is not defined by the standard. In fact it may work "correctly" (whatever that means), the standard doesn't prohibit it. That's why it is so dangerous. Because maybe in your test it works correctly, because of the hardware, OS, specific compiler, some other assumptions that take place. But the problem is that it is not guaranteed to work correctly. If you change machine, OS, a compiler (even switch optimization settings), a code slightly or even compile it two days later it may behave weirdly, in an (ekhm) undefined way.
In general there is no way to know whether a program behaves correctly or not, if UB is present. You are trying to analyze the situation by thinking about l-values, r-values, allocations, etc. while the reality is that when UB is present the entire program is meaningless. You just waste time.
Do not write UB code. Regardless of whether it seems that it works or not.