7

I'm currently reading about C++, and I read that when using return by reference I should make sure that I'm not returning a reference to a variable that will go out of scope when the function returns.

So why in the Add function the object cen is returned by reference and the code works correctly?!

Here is the code:

#include <iostream>
using namespace std;

class Cents
{
 private:
 int m_nCents;

 public:
 Cents(int nCents) { m_nCents = nCents; }

int GetCents() { return m_nCents; }
};

Cents& Add(Cents &c1, Cents &c2)
{
   Cents cen(c1.GetCents() + c2.GetCents());
   return cen;
}

int main()
{
   Cents cCents1(3);
   Cents cCents2(9);
   cout << "I have " << Add(cCents1, cCents2).GetCents() << " cents." << std::endl;

   return 0;
}

I am using CodeBlocks IDE over Win7.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
HforHisham
  • 1,914
  • 1
  • 22
  • 34
  • 6
    Because it is undefined behavior, it can appear to work fine but then break later on, it can not be relied on. – Shafik Yaghmour Aug 23 '13 at 18:37
  • 3
    What might be happening (again, with UB, anything goes) is that since after you called `Add`, you didn't call anything else, nothing has yet overridden the piece of memory where `cen` was, and so the old value is still there. That being said, you cannot rely on that always happening. – Dennis Meng Aug 23 '13 at 18:38
  • 2
    Both of those comments should probably be answers – Dan F Aug 23 '13 at 18:40
  • 1
    It will usually be overwritten when the stack grows again. Call a recursive implementation of Factorial(50) and I best it will die when you use it – Gary Walker Aug 23 '13 at 18:40
  • 1
    @DanF Alright, I'll make it an answer. – Dennis Meng Aug 23 '13 at 18:41
  • 1
    Duplicate of http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/ – digital_revenant Aug 23 '13 at 18:43
  • possible duplicate of [Returning the address of local or temporary variable](http://stackoverflow.com/questions/2744264/returning-the-address-of-local-or-temporary-variable) – Dan F Aug 23 '13 at 18:47
  • I created a new project and the code still working! – HforHisham Aug 23 '13 at 18:48
  • 1
    Just return a `Cents` instead of a `Cents&` from your `Add` and everything will work just fine and be well defined. The performance will be the same, thanks to return value optimization. – Fozi Aug 23 '13 at 18:53
  • Try running a Release build. – John Dibling Aug 23 '13 at 19:06
  • @JohnDibling yes when i did the build target: Release, and then run it printed `0 cents' , i don't know why – HforHisham Aug 23 '13 at 19:12
  • 1
    @HforHesham: It's Undefined Behavior. That's why. It could have printed `42`, washed your dog, and tuned the TV to watch soaps and it would have been equally valid. – John Dibling Aug 23 '13 at 19:27

3 Answers3

7

This is undefined behavior, it may seem to work properly but it can break at anytime and you can not rely on the results of this program.

When the function exits, the memory used to hold the automatic variables will be released and it will not be valid to refer to that memory.

The draft C++ standard in section 3.7.3 paragraph 1 says:

Block-scope variables explicitly declared register or not explicitly declared static or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
1

What might be happening (again, with UB, anything goes) is that since after you called Add, you didn't call anything else, nothing has yet overridden the piece of memory where cen was, and so the old value is still there. That being said, you cannot rely on that always happening.

Dennis Meng
  • 5,109
  • 14
  • 33
  • 36
  • And as @GaryWalker said in his comment, call anything that uses a ton of stack in between `Add` and printing it out; you'll almost certainly get garbage. – Dennis Meng Aug 23 '13 at 18:43
  • Actually you can't rely on anything at all after trying to use the dangling reference. – Ruslan May 22 '15 at 12:46
1

You should do a memcpy to copy the object being returned to heap. Though the code works, the behaviour is undefined when returning objects that go out of scope. It may always work when the code is small, because when the function returns, the portion of the stack occupied by the function will not be cleared and since the local variables within a function will have been allocated space there, the values you get (usually) contain the values you expect. But when you have multiple functions calling each other and programs grows large, your program will start producing undefined behaviour. Possibly even seg faulting at times.

Hrishi
  • 7,110
  • 5
  • 27
  • 26