1

I've got a few doubts about references in C++.

Test & returnref(){
    Test obj(9,9);
    cout << "in function: " << &obj << endl;
    return obj;
} // *

int main(){

    Test & asdf = returnref();
    Test asdf2 = returnref();
    cout << "in main asdf: " << &asdf;
    cout << "in main asdf2: " << &asdf2;

    cin.get();
    return 0;

}

the result:

in function: 0033F854
in function: 0033F854
in main asdf: 0033F854
in main asdf2: 0033F938

is it correct? in my opinion the obj is being removed on 5th line (*) - because it's alive in this function scope. so why it's working? Is it just Visual Studio? or maybe I'm wrong?

tomdavies
  • 1,896
  • 5
  • 22
  • 32
  • 5
    Your code invokes **undefined behaviour**. If it appears to work, then that's just bad luck ;) – Oliver Charlesworth Dec 24 '13 at 20:40
  • 3
    "so why it's working?" - don't worry, it's not working. It only pretends to work. –  Dec 24 '13 at 20:50
  • ok, great - I was right ;). Could you suggest me what compiler should I use to learn best practices/check what's really working and what's really not working in c++ as for references/pointers etc.? Would e.g. GCC let it go? – tomdavies Dec 24 '13 at 20:54

3 Answers3

3

You are allocating an object on the function's stack and when the function returns,

The object used is destroyed. allocate it dynamically using new(followed by a delete of course),and than

do whatever you need.

Itzik984
  • 15,968
  • 28
  • 69
  • 107
  • ok, you're right. Could you tell me whether is it a normal behaviour when I write: Test asdf2 = returnref(); (so I assign function that returns **a reference** to non-reference variable)? It creates a copy of this object then. – tomdavies Dec 24 '13 at 21:09
  • 1
    @TomDavies92 I don't know if i understood correctly, but if you want to make a copy of the object 'Test' you most likely have to define a copy constructor and a '=' operator in the 'Test' class. otherwise you will just get a shallow copy of primitive types on the 'Test' class and that's it. – Itzik984 Dec 24 '13 at 21:16
1

Using a reference to a local variable returned by a function has undefined behavior. But note that ub doesn't mean "it will crash", means "I don't know what will happen".

In your case, your calls don't reuse the memory used by that stackframe, so your local variable is still there.

Manu343726
  • 13,969
  • 4
  • 40
  • 75
1

Your options are to return by value or to return a reference/pointer to a heap-based object.

Return by value

Changing your function signature to this

Test returnval()

will copy obj. Note that the pointers you print out may still have the same value for the object inside the class and the object outside, as the compiler may have performed a return value optimisation.

If the Test class is not managing dynamically allocated resources, then you can rely on the automatically created copy constructors that the compiler will inject. If Test has dynamically allocated data, then you must write your own. See What is the Rule of Three?.

Return a pointer (or reference) to a heap-based object

You can change it to a heap-based object by using new, and then return a pointer instead:

Test* returnptr(){
    Test* obj = new Test(9,9);
    cout << "in function: " << obj << endl;
    return obj;
}

Or better yet, a smart pointer like shared_ptr to manage the deletion for you:

shared_ptr<Test> returnptr() {
    // Wrapping the pointer in a shared_ptr will ensure it gets cleaned 
    // up automatically when the last reference to it (usage of it) 
    // goes out of scope. 
    shared_ptr<Test> obj(new Test(9,9));    
    cout << "in function: " << obj.get() << endl;
    return obj;
}

Final note

As pointed out by one of the commenters on my answer, in C++11, you have further options to control how the temporary object from your function is returned by providing move constructors for Test and using std::move as necessary. This is a fairly meaty subject, but you can read more about it at the following links:

Community
  • 1
  • 1
Rob
  • 1,350
  • 12
  • 21