Below is the code which has various return statements and all are working perfectly fine. Compiler throws the warning for fun_ret_obj1
Test.cpp: In function ‘myClass& fun_ret_obj1()’: Test.cpp:45: warning: reference to local variable ‘myObj’ returned
But still the output seems to be fine.Is it by Chance?
Are there any catches with any of the return statements below?
Explanation would be really helpful, Thanks
#include <iostream>
using namespace std;
class myClass {
public:
int a ;
myClass()
{
a = 10;
}
};
myClass& fun_ret_add()
{
myClass *ptr = new myClass();
return *ptr;
}
myClass* fun_ret_ptr()
{
myClass *ptr = new myClass();
return ptr ;
}
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
int main()
{
myClass obj,obj1;
std::cout <<"In Main \n";
myClass *a = fun_ret_ptr();
std::cout<<a->a<<"\n";
myClass &b = fun_ret_add();
std::cout<<b.a<<"\n";
myClass c = fun_ret_obj();
std::cout<<c.a<<"\n";
myClass d = fun_ret_obj1();
std::cout<<d.a<<"\n";
}
First one is a memory leak:
myClass& fun_ret_add()
{
myClass *ptr = new myClass();
return *ptr;
}
Second one returns a raw pointer (evil - return a std::unique_ptr)
myClass* fun_ret_ptr()
{
myClass *ptr = new myClass();
return ptr ;
}
Third one is perfect - returns a copy, which will almost always be elided. In c++17 it's guaranteed to be elided. This is efficient and safe.
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
update
In c++17 you could guarantee the elision of the copy this way:
myClass fun_ret_obj()
{
return myClass{};
}
end of update
Fourth one is undefined behaviour. Returning a reference to a non-existent object. Never do this.
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
It is true that in the first example, a caller could release the memory if he/she knew that myClass had been allocated with new
:
auto& x = fun_ret_add(); // a
...
delete std::addressof(x); // b
This would require:
The second example is similar. In this case, at least there is a hint that the object needs to be deleted, but the caller must still know that the object has been allocated with new
, and he must guard against exceptions.
Contrast with this:
std::unique_ptr<myClass> fun_ret_ptr()
{
return std::make_unique<myClass>();
// or
return { new myClass() };
// or
return std::unique_ptr<myClass>(new myClass());
}
Now the caller receives a smart pointer. If the caller does nothing but use this pointer, the myClass object will be properly deleted when the pointer goes out of scope, and all memory will be reclaimed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With