-3

Let foo be:

class Foo {
public:
    Foo(int a) {
        aa = a;
        cout << "foo built. " << aa << endl;
    }
    ~Foo() {
        cout << "foo DIED. " << aa << endl;
    }

    int aa;
};

Also, assume we have:

Foo* func1(){
    Foo* foo = new Foo(1);
    return foo;
}

Now, running this:

{ // <---- we have braces
    Foo obj = *func1();
}

yields: "foo DIED"

but running:

{
    Foo &obj = *func1();
}

does not release foo's instance.

Could you please clarify what's happening here?

salehjg
  • 49
  • 1
  • 9
  • It does compile and it seems that -fpermissive is present (by default in VS) – salehjg Mar 30 '23 at 20:10
  • 5
    You seem to be asking what the difference is between a **reference** and an **object**. In a very roundabout way. – Drew Dormann Mar 30 '23 at 20:11
  • https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – 463035818_is_not_an_ai Mar 30 '23 at 20:12
  • 2
    *yields: "foo DIED"* -- Do you know which `foo` object died? The one dynamically allocated is still alive. If you want to know what object is created or destroyed, you should be ouputting the value of `this`, not just a simple message. – PaulMcKenzie Mar 30 '23 at 20:13
  • I am familiar with a reference, but I do not understand why this code compiles and why I get two different behaviors. @DrewDormann – salehjg Mar 30 '23 at 20:14
  • 2
    Add instrumentation to `Foo`'s copy constructor and you'll see that the first makes a copy and the second doesn't. – Miles Budnek Mar 30 '23 at 20:14
  • 2
    @salehjg Both code snippets compile because they are legal code. `func1()` returns a `Foo*` pointer to a dynamic `Foo` object, which both code snippets are leaking. However, the 1st snippet is *copying* that object to another local `Foo` object, then the *copy* gets destroyed afterwards, hence the "died" message. Whereas the second snippet just takes a reference to the original `Foo` object, no copy is made, thus nothing "dies". – Remy Lebeau Mar 30 '23 at 20:16
  • btw you should neither use `new` nor return the `Foo*` as raw pointer from the function. – 463035818_is_not_an_ai Mar 30 '23 at 20:18
  • 3
    `cout << "foo built. " << aa << " " << this << endl;`-- `cout << "foo DIED. " << aa << " " << this << endl;`. Now you will see a mismatch of construction and destruction, all because you didn't track the creation of the copy. – PaulMcKenzie Mar 30 '23 at 20:18
  • @RemyLebeau Thank you! Your comment answered my question completely. Post it so I can accept it. – salehjg Mar 30 '23 at 20:19
  • @salehjg I can't post an answer unless the question is re-opened first. – Remy Lebeau Mar 30 '23 at 20:19
  • @RemyLebeau go for it. – Drew Dormann Mar 30 '23 at 20:23
  • @DrewDormann looks like someone already beat me to it – Remy Lebeau Mar 30 '23 at 20:34
  • Dumb luck. I had the answer mostly written when the question was closed. It was still cached when the question re-opened. – user4581301 Mar 30 '23 at 20:38

1 Answers1

2

func1 allocates a Foo and returns a pointer to it. Sooner or later someone must manually delete that Foo to free up the resources it uses. Because *func1() dereferences the pointer before a copy of the pointer is made, the pointer is lost. Without the pointer, the object could be lost forever, preventing you from deleteing it when you no longer need it.

Foo obj = *func1(); resulted in the creation of two Foos. The one dynamically allocated in func1 and another automatically allocated Foo named obj that is a copy of the Foo from func1. It is the death of obj when it goes out of scope that you are seeing. The Foo from func1 has been lost. You have what's called a memory leak. This code cannot be fixed. It is broken, even though it's the one that looked like it worked.

Foo &obj = *func1(); creates one Foo, the one from func1, and obj merely references it. When the reference goes out of scope nothing happens. You can't refer to the object as obj anymore, the reference is no more, but the object still exists in memory and has been leaked. But in this case while you still have obj referencing it, you can delete &obj; and free it.

{
    Foo &obj = *func1();
    delete &obj; // get address of referenced object, then delete it.
}

Now you can see the object being freed.

Long-and-short: You always have to keep a live reference or pointer to a dynamically allocated object until you manually release it.

user4581301
  • 33,082
  • 7
  • 33
  • 54