7

I am new to C++ and I'm stuck at the following problem:

Imagine you have a function that creates a new object and returns this object. What is the best approach to do that? I have found 3 different solutions.

Solution 1 Using the copy constructor

MyClass getMyClass() {
    MyClass obj;
    //work with obj, set values...
    return obj;
}

As far as I understod it, you create a new object, copy that object, destroy the first and return the copied object. So I created two object, but I only needed one. Is that right?

Solution 2 Creat the object on the heap and use pointer

MyClass* getMyClass() {
    MyClass* obj = new MyClass();
    //work with obj, set values...
    return obj;
}

This seems to be the worst solution, you have to do memory management on your own.

Solution 3 Pass the object as a parameter

MyClass getMyClass(MyClass& obj) {
    //work with obj, set values...
    return obj;
}

You create a default object and set all values in the function.

I also thaught about using unique_ptr<MyCLass> but there is the same problem, that the unique_ptr is destroyed when the function scope is left.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Ennosigaeon
  • 442
  • 7
  • 15
  • You should consider shared_ptr http://www.cplusplus.com/reference/memory/shared_ptr/ also you could use move semantics http://www.cplusplus.com/reference/algorithm/move/ – Florian Groetzner Apr 30 '14 at 09:32
  • In the case of solution 1, the compiler should be able to apply Named Return Value Optimization and construct the object at its final destination. – Michael Apr 30 '14 at 09:34
  • For solution 2 use a `std::shared_ptr`. All three solutions have their use cases, there's none of them to prefer generally. – πάντα ῥεῖ Apr 30 '14 at 09:35
  • @Dlotan No, you should only consider a `shared_ptr` if you want shared ownership. This is rarely the case. – juanchopanza Apr 30 '14 at 09:35
  • "the `unique_ptr` is destroyed when the function scope is left" - unless you return it from the function. `unique_ptr` is movable. – Mike Seymour Apr 30 '14 at 09:38
  • Unless you **know**, and know **exactly**, that solution 1) is **not** sufficient for your needs, use solution 1). It is the "natural" way to do it, *much* less error-prone than the other two, and given a compiler's return value optimization, not half as much a performance issue as you might think. – DevSolar Apr 30 '14 at 09:38
  • in the 3rd solution, didn't you mean: void getMyClass(MyClass& obj) { //work with obj, set values... } ? – Youda008 Apr 30 '14 at 10:10
  • @Youda008 Yes, you are right – Ennosigaeon Apr 30 '14 at 10:21

2 Answers2

9

Solution 1 does not use the copy constructor but return value optimization. It means that the object constructed in the function is actually not copied but passed to the caller of the function directly. Solution 1 is a very good option which I would recommend for non-polymorphic objects (i.e. no inheritance) which do not use too much space on the stack.

The preferred method for polymorphic objects would be Solution 2. But always think about who owns your objects, i.e. who is responsible for calling delete. A good alternative is using shared_ptr or unique_ptr.

Solution 3 does not really create the object, it only works with it once it is already created. It also does not make sense to return the object here.

Danvil
  • 22,240
  • 19
  • 65
  • 88
0

Each of these has its own use cases, you can't say that one of them is better than the other or worst in all circumstances. It all boils down to your objects, how you create them, what are they supposed to interface to and where are they used.

And also there is the fourth, returning by using a shared pointer shared_ptr (in case you need shared ownership) or an auto pointer (unique_ptr or auto_ptr (sort of deprecated) ).

For example the one taking in a reference does not need to return the object too, that's an extra operation.

The one returning a pointer might not need to include a header file, a simple forward declaration might be enough (at least when you declare the function in the header file). But for this of course you will need to manually manage the memory (again: shared pointers might help here).

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167