Dangling Reference work perfectly!

Hi
In a c++ book, I have found an example of Dangling Reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

const int& min(const int& i1,const int& i2)
{
    if(i1 < i2)
    	return i1;
    return i2;

}
//---------------------------------------------------------------------------
int main()
{
    const int & i = min (1+2,3+4);
    cout << i;
    return 0;
}


This code should not work, but it works!
I think it makes sense. Compiler allocates read only memory for const values of 3(1+2) and 7(3+4) first, then passes them to min(), they are not dangling references. Maybe the book is dated.
You have mentioned that the book is out of date.

The book was released in 1995 and I have got the final edition 2003.

According to this it is waste of time to study the book which are release before 1999?

I have the same issue with this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

double & Getsomenumber()
{
double number = 12.4;

double &anotherNumber = number;

return anotherNumber;
}
//---------------------------------------------------------------------------
int main()
{
    const double  & i = Getsomenumber();
    cout << i;
    return 0;
}
Last edited on
Yes there is an issue with that code.
You are returning a reference to a local variable.

In the simple example you wrote - it will semm to work - but the result should be considered 'undefined'

Returning a pointer to or a reference to a local variable is a no-no
Last edited on
closed account (1vRz3TCk)
The book was released in 1995 and I have got the final edition 2003.

According to this it is waste of time to study the book which are release before 1999?

What is the book?

I have the same issue with this code:

As guestgulkan said it only appears to work, here is why it doesn't [1]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

using namespace std;

double & Getsomenumber()
{
    double number = 12.4;
    double &anotherNumber = number;
    return anotherNumber;
}

void SomeFunc()
{
    double a_num = 0;
}

int main()
{
    const double  & i = Getsomenumber();
    SomeFunc();
    cout << i;
    return 0;
}


[1] this should show an output of zero, but may not.
closed account (zb0S216C)
Constant references accepts literals. Numerical literals don't have an address in memory, so returning a literal is safe. Literals are not local to any function. The values given to i1 and i2 are results of a constant expression. Now, i1 and i2 are constant references to literals, not local objects.

alend wrote:
1
2
3
double &anotherNumber = number;

return anotherNumber;
(sic)

The value of anotherNumber is returned. When the invocation of Getsomenumber( ) is finished, all local variables (including the parameters) are popped from the stack. This occurs when the return statement of the function does its thing. The dangerous part is when you refer to that returned object with a reference because anotherNumber is gone, thus leaving the reference referring to an address where anotherNumber used to be, hence, undefined behaviour.

Wazzak
closed account (1vRz3TCk)
Framework wrote:
Constant references accepts literals. Numerical literals don't have an address in memory, so returning a literal is safe...
The problem with calling const int & i = min (1+2,3+4); is that temporaries are created and a reference to one of the temporaries is taken.
Last edited on
¿why is that a problem? I think that you can extend the lifetime of temporaries using constant references.

I found weird that gcc doesn't complain about the second code.
closed account (1vRz3TCk)
¿why is that a problem? I think that you can extend the lifetime of temporaries using constant references.
Constant References can prolong the lifespan of temporaries. I'm not entirely sure of the rules but I believe it is not is not transitive through a function argument.

I may be wrong. :0)

Edit:
I have just looked it up in the standard and I am still not sure.
12.2 Temporary objects
...
4 There are two contexts in which temporaries are destroyed at a different point than the end of the full expression...
5 The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call. A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits. In all these cases, the temporaries created during the evaluation of the expression initializing the reference, except the temporary to which the reference is bound, are destroyed at the end of the full-expression in which they are created and in the reverse order of the completion of their construction.
Last edited on

The book was released in 1995 and I have got the final edition 2003.
According to this it is waste of time to study the book which are release before 1999?

Dated book is not simply a garbage that wastes your time to read it, it can always give you major concepts and history of things.


I think it makes sense. Compiler allocates read only memory for const values of 3(1+2) and 7(3+4) first, then passes them to min()

I'd correct my words above as it's not correct. I thought that compiler dealing with min(1+2, 3+4) is same as dealing with aFunc("abcd"). string "abcd" is allocated in read only memory for sure, but 3(1+2) and 7(3+4) aren't, they are allocated in the stack, as CodeMonkey said, they are temporary object, in other word, compiler treats them as local variables of main(). I revised the alend's first example as below that can clearly explain what I said here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const int& min(const int& i1,const int& i2)
{
    if(i1 < i2)
    	return i1;
    return i2;

}

const int & test()
{
    const int & i = min (1+2,3+4); // 3(1+2) and 7(3+4) are local variables in test() function
    cout << i; // so i is always a good reference and giving correct value here
    return i;
}

int main()
{
    const int & j = test(); // j will have a dangling reference
    return 0;
}
I think the compiler will optimise away the 1+2 and 3+4 so that you just have 3 and 7 as inputs.

These are constant literal values so they will be stored somewhere in the executable, so they do have an address.

If code generates this much head scratching then its bad anyway - keep it simple!
int *foo() (int var=0;return &var;} //bad!
int &foo() (int var=0;return var;} //bad!

"The store is reused after the function returns, so pointer to the local variable should never be returned"
The C++ Programming Language (Bjarne Stroustrup)

Therefore, although the result is correct at a moment, it may change later!


In C++ const reference is a kind of hybrid. if there isn't a variable of that type associated then a local variable is generated and the appropriate constructor is called. Thus a const reference can never be a 'dangling' reference.

This const int &t(300); works too!
Topic archived. No new replies allowed.