Option 1 is defective. When you declare an object
QList<Weight *> ret;
it only lives in the local scope. It is destroyed when the function exits. However, you can make this work with
return ret; // no "&"
Now, although ret
is destroyed, a copy is made first and passed back to the caller.
This is the generally preferred methodology. In fact, the copy-and-destroy operation (which accomplishes nothing, really) is usually elided, or optimized out and you get a fast, elegant program.
Option 2 works, but then you have a pointer to the heap. One way of looking at C++ is that the purpose of the language is to avoid manual memory management such as that. Sometimes you do want to manage objects on the heap, but option 1 still allows that:
QList<Weight *> *myList = new QList<Weight *>( getWeights() );
where getWeights
is your example function. (In this case, you may have to define a copy constructor QList::QList( QList const & )
, but like the previous example, it will probably not get called.)
Likewise, you probably should avoid having a list of pointers. The list should store the objects directly. Try using std::list
… practice with the language features is more important than practice implementing data structures.
While this isn't exactly invalid, it's not a good idea.
MyClass& doSomething() {
return *(new MyClass());
}
After you return, nobody has the original pointer, so nobody will ever delete
it.* So it's a memory leak.
You should pretty much never write a new
unless you have a corresponding delete
—or, better, a smart pointer constructor.
Meanwhile, this line in your original code:
MyClass a = doSomething();
… is going to make a copy of the value anyway. Assuming that wasn't another bug that has to be fixed, why bother heap-allocating an object and returning a reference to copy and leak? Just return the object by value:
MyClass doSomething() {
return MyClass();
}
Now you don't have to worry about deleting anything, because you never created anything on the heap.
Best practices can usually be summed up in the four letters RAII: Resource Acquisition Is Initialization. (And the corollary, that destruction is release.) If you have something that's impossible, or expensive, to pass around by value, then pass around some handle to it by value. For example:
unique_ptr<MyClass> doSomething() {
return unique_ptr<MyClass>(new myClass());
}
unique_ptr<MyClass> a = doSomething();
Now it's just a pointer being copied around. The object itself gets created inside doSomething
, and deleted whenever a
goes out of scope (or, if you pass it along to another variable, whenever that goes out of scope, etc.).
On the other hand, if MyClass
is just a handful of easily-copyable values**, just copy it.
* It's not impossible to ever delete it; you can always take a pointer to the reference and delete
that. It's just very unlikely you will ever do so, and it will look awkward. If you want to pass pointers around, pass pointers around. If you don't want to pass pointers around, wrap ownership up in a class and pass the class around by value.
** By "easily-copyable" I mean that it's easy to copy them safely, and that you actually do so. For example, a raw pointer or a file handle is just a few bytes, and the default copy constructor will gladly copy them over for you… but then you end up with multiple references to the same heap object or file, and it's impossible to track who's in charge of deleting or closing it.
Best Answer
You can't return a reference to a temporary object on the stack. You have three options:
Note that when you return by value as in the code below, the compiler should optimize the assignment to avoid the copy - i.e. it will just create a single Rectangle (rect) by optimizing the create+assign+copy into a create. This only works when you create the new object when returning from the function.