4

I'd like to know what is considered nowadays the best practice when returning a pointer to a polymorphic object from a function, for example when using factories. If I transfer the ownership, should I return boost::unique_ptr<Interface>? What should I return if I don't transfer the ownership (e.g. returning a reference to a member)? Is there an alternative, non boost-based way which is also commonly used? Thanks.

EDIT: it is supposed to be C++03 compatible, with a possibility to easily upgrade to 0x

EDIT2: Please note I'm explicitly asking about common approaches, best practices, and not just "a way to do this". A solution implying a conditional search-and-replace over the codebase in future does not look like a good practice, does it?

EDIT3: Another point about auto_ptr is that it is deprecated, whatever neat it is, so it looks strange to advertise its usage at the interface level. Then, someone unaware will put the returned pointer into a STL container, and so on and so forth. So if you know another somehow common solution, you are very welcome to add an answer.

Roman L
  • 3,006
  • 25
  • 37
  • You can complain all you want about how `::std::auto_ptr` is deprecated, the fact is you can't do any better without overhead, or narrowing the interface. If you use `::std::tr1::shared_ptr` you get reference counting when you don't need it. Really `::std::auto_ptr` is the only reasonable solution available in C++. `::boost::unique_ptr` simply removes the problematic operations from `::std::auto_ptr`. And while some might consider that better, it's a third-party library, and I couldn't recommend the use of a third party library as a 'best-practice' unless there was no alternative. – Omnifarious Jan 20 '11 at 17:42
  • @Omnifarious: I appreciate you answer, but I'm also trying to encourage other people to share their opinion. – Roman L Jan 20 '11 at 17:50
  • Is there some reason you are not considering `shared_ptr` for this? – Zac Howland Jan 20 '11 at 18:21
  • @Zac: I don't mind considering shared_ptr, but I'd like to use a common solution. I.e. if many people use shared_ptr in interfaces and it is reasonable, I could also use it. I doubt that it is common, though, because shared_ptr is quite complex and has an overhead. – Roman L Jan 20 '11 at 18:28
  • It really depends on what you are doing. `auto_ptr` is a bad solution in several circumstances for several reasons (not even mentioning that it is deprecated) - for example, if you are storing the interface pointers in a collection, you can't use `auto_ptr`. From the sounds of it, you are asking for a "best practice" that doesn't really exist. How you approach the solution really depends on how you intend your factory method and the interface it returns to be used. – Zac Howland Jan 20 '11 at 18:38
  • @Zac: You are right, and that's why I referred to `unique_ptr`, and not to `auto_ptr`. I just need to decide what to return from factory functions. I know the "old" way which you find in many books is to return raw pointers, and I'd like to know if there is a modern common replacement for that, taking care of the ownership problem. – Roman L Jan 20 '11 at 18:45
  • 1
    In most cases, I find that 'shared_ptr` works well when returning from a factory. It allows the object to take ownership of itself and maintains the ability to do things like operate on a set of these interface pointers. The minor overhead of reference counting is not even noticeable on most systems (the exception being embedded systems - where you're likely to be using C instead of C++ anyway). – Zac Howland Jan 20 '11 at 19:05
  • @Zac: Well, you can use shared_ptr anywhere where you could use unique_ptr, but the question is which one is more appropriate and common. – Roman L Jan 20 '11 at 19:30
  • `unique_ptr` is fairly new (by comparison) so `shared_ptr` would be more common simply because of age. But, like I said before, it will really depend on how you want to use the result of the factory method. – Zac Howland Jan 20 '11 at 19:33
  • @Zac: You can convert an auto_ptr or a unique_ptr to a shared_ptr if you need it, so it seems more natural to return the simplest object. See here for some similar thoughts: http://stackoverflow.com/questions/1770636/shared-ptr-vs-scoped-ptr – Roman L Jan 20 '11 at 19:37
  • Using a `unique_ptr`, that isn't a big deal. `auto_ptr` is anything but a "simple" pointer wrapper in that there are a lot of issues you have to be careful about when using them. Use what you feel will meet your needs best. – Zac Howland Jan 20 '11 at 19:44
  • @Zac Howland - I resent interfaces that force me to pay an unnecessary price. If there is a good reason the interface should use `shared_ptr` apart from simple convenience, that's fine. But if it's just convenience and a feeling that really, nobody should be caring about the cost except group X who we aren't targeting this at anyway, that means I'm a member of group X regardless of whether or not the implementor thinks I ought to be. – Omnifarious Jan 20 '11 at 20:45

1 Answers1

4

Use ::std::auto_ptr for now, and when C++0x is available, then switch to ::std::unique_ptr. At least in the factory case where you are handing ownership back to the caller.

Yes ::std::auto_ptr has problems and is ugly. Yes, it's deprecated in C++0x. But that is the recommended way to do it. I haven't examined ::boost::unique_ptr, but without move semantics I don't see that it can do any better than ::std::auto_ptr.

I prefer the idea of upgrading by doing a search and replace, though there are some unusual cases in which that won't have the expected result. Fortunately, these cases generate compiler errors:

::std::auto_ptr<int> p(new int);
::std::auto_ptr<int> p2 = p; 

will have to become at least like this

::std::unique_ptr<int> p(new int);
::std::unique_ptr<int> p2 = ::std::move(p);

I prefer search and replace because I find that using macros and typedefs for things like this tend to make things more obscure and difficult to understand later. A search and replace of your codebase can be applied selectively if need be (::std::auto_ptr won't go away in C++0x, it's just deprecated) and leaves your code with clear and obvious intent.

As for what's 'commonly' done, I don't think the problem has been around for long enough for there to be a commonly accepted method of handling the changeover.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • 2
    +1 -- `std::auto_ptr` is awesome despite people bashing it all the time. – Billy ONeal Jan 20 '11 at 17:00
  • Well, but how do I switch to it then, by search-and-replace all over my code? – Roman L Jan 20 '11 at 17:00
  • @7vies: Assuming the boost dependency isn't a problem just continue using boost, except where you must transfer ownership. Otherwise you're going to have to do the search and replace. – Billy ONeal Jan 20 '11 at 17:02
  • @7vies: Added the answer to that question to my answer. – Omnifarious Jan 20 '11 at 17:05
  • 1
    Search-and-replace looks like a very ugly way of doing it, initially using a typedef or even a macro looks better to me :\ Is what you are suggesting really the best practice, or just one of the ways of doing it? – Roman L Jan 20 '11 at 17:08
  • @7vies: Yes, those both could work. Though they basically just narrow down where the search and replace has to happen. :-) A macros would let you just change the token `auto_ptr` to whatever you wanted. That would probably be good enough for most purposes. – Omnifarious Jan 20 '11 at 17:10
  • @Omnifarious: Sorry but I'm asking for the *best practice*, not for *a way* to do this, I already do know the different options and the problem is to choose. – Roman L Jan 20 '11 at 17:12
  • @7vies: I don't think anybody has come up with any 'best-practices' involving the changeover. There is very definitely a best practice when it comes to returning objects polymorphically when ownership transfer is implied, and I gave it. But there are no best practices I'm aware of for how to handle changing from one to the other when C++0x arrives. Personally, I'd prefer search and replace to a macro or typedef. – Omnifarious Jan 20 '11 at 17:21