5

Possible Duplicate:
how to “return an object” in C++

Hello, guys!

If I need to return an object from function (and it is not a getter, and also this function for some reason cannot be implemented as a constructor, for example there is a constructor with the same signature and different semantics), how better to implement this?

For example, one can propose the following options:

1) Return an object itself:

MyClass GetMyClass() {
    MyClass a;
    ...
    return a;
}

In most cases RVO, http://en.wikipedia.org/wiki/Return_value_optimization is performed, no copy constructors is called and there is no overhead. The drawback of this approach is that despite RVO, you must specify the copy construtor of MyClass, but as mentioned in Google C++ Style Guide...

Implicit copying of objects in C++ is a rich source of bugs and of performance problems.

2) Return a pointer to an object:

MyClass* GetMyClass() {
    MyClass* a= new MyClass();
    ...
    return a;
}

In such case, there is an overhead because of allocating memory on heap. This somehow slows down the program due to malloc system call. Also, you should free memory outside of this function, which means that allocating and releasing performed in different logical units. As mentioned here, Why malloc memory in a function and free it outside is a bad idea? it is more often a bad idea.

3) Pass value by reference or by pointer:

void GetMyClass(MyClass& a) {
    ...
}

In this case, code becomes ugly and poorly readable

What is the best practice? Which one do you use in your projects and which criteria are the most important when you are working on a big project?

Community
  • 1
  • 1
EGeorge
  • 148
  • 8
  • 1
    (2) and (3) aren't really feasible, so there's not much choice left. (2) is outright terrible for lots of reasons, and (3) requires the existence of a default-constructor, which is gratuitous. – Kerrek SB Nov 02 '12 at 19:58
  • 4
    Don't we have && and move constructors nowadays? – amaurea Nov 02 '12 at 19:59
  • Why (3) requires the existence of a default-constructor? – EGeorge Nov 02 '12 at 20:01
  • You missed return by reference.....!!! – Coding Mash Nov 02 '12 at 20:02
  • 3
    Also, don't use Google's style guide. It's for Google's old codebase. Use what's *smart*, which may coincidentally be some of those things (but not likely). And no, very rarely should you need to specify a copy constructor. Resource-managing classes will follow the Rule of Three, everything else will Just Work. – GManNickG Nov 02 '12 at 20:03
  • @user1771139: It doesn't require a default constructor *exactly*, but it requires you have an object already in existence, which is wasteful to create just to have your function reassign it. – GManNickG Nov 02 '12 at 20:04
  • 1
    I agree with @KerrekSB: #1 is the only real choice here. The quote from the Google style guide is half wrong (and the other half is obsolete). – Jerry Coffin Nov 02 '12 at 20:08
  • 1
    @CodingMash: I didn't mentioned it because on my opinion there are too many drawbacks and pitfalls, so it is not an option – EGeorge Nov 02 '12 at 20:12
  • @user11771139 Sometimes, there is almost no option for it otherwise. As in the case of overloaded `operator=`. – Coding Mash Nov 02 '12 at 20:13
  • Sorry, not "default constructor", but rather "a constructed object", *and* assignment. Apologies. But that's equally gratuitous. – Kerrek SB Nov 02 '12 at 20:13
  • @GManNickG: What is meant by Resource-managing class? Is there some formal definition? – EGeorge Nov 02 '12 at 20:16
  • @CodingMash: The only case I know when returning by reference may be applied is operators, when you return reference on *this, are there another use cases? – EGeorge Nov 02 '12 at 20:22
  • @user1771139: No, but it's something like `shared_ptr` or `std::vector`, a thing that has a destructor ([and therefore a copy-constructor, assignment operator, etc.](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three)). – GManNickG Nov 02 '12 at 20:27
  • @user1771139 whenever a situation arises when we change the value of the object and have to return `*this`, we return by reference... There could be cases apart from operator overloading as well. – Coding Mash Nov 02 '12 at 20:33
  • @amaurea thank you, I've read about move constructors only after your comment. And what do you mean by &&? – EGeorge Nov 02 '12 at 20:35
  • @CodingMash: could you please give an example of such case, when it is insufficiently to write a usual method, because it, maybe because of lack of experience, really doesn't came to my mind – EGeorge Nov 02 '12 at 20:49

2 Answers2

4

Two is pretty straightforward. Yes, malloc can be slow, but does it matter in your case? You need space for that object from somewhere. Also note the answers in the question you point to, it's only across logical units that there is an issue. See if you have the problem and then try to fix it rather than pre-optimizing.

You could potentially make your own version of new that uses a free store and managers resources itself. However, unless you've measured and found new to be a problem it's error prone.

One way you can help ameliorate problems with freeing pointers is by using a std::shared_ptr. That way you don't have to worry about freeing the object as long as you always use it through the smart pointer.

Paul Rubel
  • 26,632
  • 7
  • 60
  • 80
  • If I got you right, you suggest to use std::shared_ptr or to write our own memory manager? – EGeorge Nov 02 '12 at 20:29
  • That's true, under the condition that this is really a problem. Writing your own manager is a non-trivial undertaking and you want to make sure that by writing it you're addressing your most pressing problem. new or a smart pointer of some kind is simple and easy, be sure to try that first. – Paul Rubel Nov 05 '12 at 14:44
2

You omitted the obvious opportunity of returning a move constructible object: return value may still reduce overhead in many cases but you don't run the risk of accidental copies. Where C++ 2011 isn't available, I would make the type copyable and return by value.

Where neither move nor copy is an option, I would return a pointer. Of course, I wouldn't return a naked pointer but a std::unique_ptr<T> (or std::auto_ptr<T> where unavailable): Using a smart pointer avoids the risk of a memory leak but the choosing a lightweight pointer rather than, e.g., std::shared_ptr<T>, doesn't make a final policy decision on how the object is maintained. In cases where the object needs to be released in some funny way it may come with a deleter.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380