Hi guys,

Your typical C++ beginner here. I'm using the renowned Deitel C++: How to program to learn C++. I am my own mentor and here's what I can't comprehend:

What's a Dangling Reference?

According to Deitel C++: How to Program and I quote "Functions can return references, but this can be dangerous. When returning a reference to a variable declared in the called function*, the variable should be declared STATIC within that function. Otherwise, the reference refers to an automatic variable that is discarded when the function terminates; such a variable is said to be "undefined" and the program's behavior would be unpredictable."

*Called function or the function to whom we return e.g main()?

It would be nice if someone could elaborate on what a Dangling Reference is and provide a code example too. I googled but found nothing helpful or comprehensible.

Thank you for your time.

Recommended Answers

All 11 Replies

double & Getsomenumber()
{
    double number = 12.4;

    double &anotherNumber = number;

    return anotherNumber;}

As soon as this function ends, the variable number is removed and no longer exists. What does the returned reference actually refer to? Something that no longer exists.

double & Getsomenumber()
{
    double number = 12.4;

    double &anotherNumber = number;

    return anotherNumber;}

As soon as this function ends, the variable number is removed and no longer exists. What does the returned reference actually refer to? Something that no longer exists.

So I must declare the variable "number" as static if I want to assign it's value to a variable in .main(). OK alright understood.

One more thing you inserted an ampersand before the function name. Is that because you're return a reference / pointer? just making sure i have not come across this in my book yet.

Thank you again.

Sure, you could make it static. Alternatively, you could just return the value like I expect you're used to:

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

or in this case, just

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

When you get to references you'll see the uses of the "&" in this context.

The paragraph you cite is an example of explaining how to avoid a bad programming technique by using a second bad programming technique. Here's why I say that.

A reference is an alternative name for an object. For example, if I write

int i;
int& j = i;

then I am saying, in effect, that j is an alternative name for i; in other words, that i and j are two different ways of referring to the same object.

When you write a function that returns a reference, that function is returning an alternative name for an object somewhere, because that is what a reference is. For such a function to be meaningful, it must return a reference to an object that will continue to exist after the function has returned.

So, for example, if I write the following:

int& foo()
{
    int n;
    return n;    // Don't do this!!
}

I have written a function that behaves in an undefined way when I call it. The reason is that if I write

int& x = foo();

I am saying that I want x to be an alternative name for whatever foo returns. However, what foo returns is an alternative name to its local variable n, and that variable ceases to exist when foo returns. Therefore, it returns an alternative name for something that does not exist, and x is similarly caused to name a nonexistent object.

The bad programming technique here is returning a reference to an object that no longer exists. Deitel replaces that error by another:

int& bar()
{
    static int n;
    return n;     // Don't do this either!
}

Technically speaking, there is nothing wrong with this code: It returns a reference to a variable that will continue to exist indefinitely. However, this example has replaced the previous example's flagrant error by a subtle one--and being subtle, it is that much harder to find.

The error is that every call to bar will return a reference to the same object. So, for example, if I write

int& i = bar();
int& j = bar();

the names i and j now refer to the same object; changing one of them will change the other. Unless this is what I had in mind when I wrote the bar function, I am apt to spend a long time looking for the bug.

Therefore, I think it is bad advice to say "Whenever you write a function that returns a reference to a local variable, make that variable static." Instead, I would give the following advice:

When you write a function that returns a reference, ask yourself why you want it to return a reference. Remember that the reference that it returns must refer to an object that will outlive the function itself, and think about why it is important to return a reference, and about the use to which you will put that reference. Once you understand these aspects of your program, you will be able to figure out where that reference should refer, and why.

But until you've done that planning, and until you understand what you're trying to do that thoroughtly, following a rule of thumb such as "If you return a reference to a local variable, make that variable static" will just take obvious problems and turn them into subtle ones that will take a long time to find.

int function( void )
{
  int number = 100;
  int &nRef = number;
  return nRef;
} 

int main( void )
{
  int mainVar = function();
  cout << "Output: " << mainVar << endl;
}

When I run this code I get "Output: 100" even tough variable number is an automatic variable that is popped off the stack before returning to main().

Why is that so? I'm using GNU G++ - Cygwin.

Off the top of my head, it's pure chance that the lump of memory being referred to has not yet been written over with something else.

@DonutsnCode: Line 1 of your function says it returns int, not int&. It might still appear to work if you change it, but there's nothing wrong with the code you posted.

Thanks guys, you were really helpful there.

@OP: Usually you should avoid the usage of static keyword. To further explain the problem consider what happens here :

int x = 10;
int &y = x;
y = 20; //x = 20 as well

Since y is a reference to x. Changing y will also change x. Basically, y is another name for x.

Now what happens when x is not valid, meaning when it goes out of scope? For example
this function shows such a case:

int& getFive(){
 int x = 5;
 return x;
}

and call it like so int& y = getFive(); . Now just like in the other y is a reference to x. But this time x is not valid. x is not valid because it goes out of scope and the compiler destroys it. Here is a psuedo-sequence of what happens in the above call to getFive();
1) y is declared as a reference to getFive();
2) getFive() gets executed
3) Inside getFive() the variable x gets created and initialized to 5. Since x is not declared static, you tell the compiler that it goes out of scope at the end of the function and thus should get destroyed and free the memory it occupies.
4) Now you try to return x. But the function says that return x as a reference so the compiler possibly tries to return x as a reference but you told the compiler to destroy x when it goes out of scope at the end of the function, so essentially, you are asking the compiler to return a reference to a variable that has been destroyed already. Now y points who knows what. It could point to anything since the behavior is undefined meaning that the compiler can do anything it wants.

And that is your problem. The main point is that you should not return a reference to a variable that goes out of scope before its being referenced

EDIT: Ninja'd

Thank's again you guys, you really flushed the ambiguity out of my brain when it come to this dangling reference thing.

This thread is now solved!

Thanks for this excellent post. It helped a lot. I too had wondered about the Deitel paragraph cited above. I have one question. See code below...

int&
foo (int x)
{
  int n = x ;

  return n ; // Don't do this!!
}

int
main (int argc, char** argv)
{
  int &fooRef1 = foo (1) ;
  cout << "fooRef1: " << fooRef1 << endl ;
  foo (1001) ;
  cout << "fooRef1: " << fooRef1 << "  Oops!" << endl ;

  cout << "*************" << endl ;

  int &fooRef2 = foo (2) ;
  cout << "fooRef2: " << fooRef2 << endl ;
  int &fooRef3 = foo (1002) ;
  cout << "fooRef3: " << fooRef3 << endl ;
  cout << "fooRef2: " << fooRef2 << "  Oops!" << endl ;

  cout << "*************" << endl ;

  int &fooRef4 = foo (3) ;
  cout << "fooRef4: " << fooRef4 << endl ;
  int fooInt = foo (1003) ;
  cout << "fooInt: " << fooInt << endl ;
  cout << "fooRef4: " << fooRef4 << endl ;
  return 0 ;
}

Take a look at the line toward the bottom:
int fooInt = foo (1003) ;

When I look at the subsequent fooRef4 it's value is 3; not 1003. So in the case where foo() returns to a plain ole int (not a reference) as seems to be perfectly legal the value of fooRef4 does not get stepped on as I had seen in the prior two experiments. Does anyone have any idea why? Is this because there's an implicit cast going on under the hood? Thanks in advance.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.