56

Is there some equivalent class for C++1x's std::unique_ptr in the boost libraries? The behavior I'm looking for is being able to have an exception-safe factory function, like so...

std::unique_ptr<Base> create_base()
{
    return std::unique_ptr<Base>(new Derived);
}

void some_other_function()
{
    std::unique_ptr<Base> b = create_base();

    // Do some stuff with b that may or may not throw an exception...

    // Now b is destructed automagically.
}

EDIT: Right now, I'm using this hack, which seems like the best I can get at this point...

Base* create_base()
{
    return new Derived;
}

void some_other_function()
{
    boost::scoped_ptr<Base> b = create_base();

    // Do some stuff with b that may or may not throw an exception...

    // Now b is deleted automagically.
}
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Clark Gaebel
  • 17,280
  • 20
  • 66
  • 93
  • Also, can this effect be created by making the copy constructor have move semantics, then the destructor checks before freeing? – Clark Gaebel Jun 01 '10 at 21:42

5 Answers5

71

It's not possible to create something like unique_ptr without C++0x (where it's part of the standard library, and so Boost doesn't need to provide it).

Specifically without rvalue references, which are a feature in C++0x, a robust implementation of unique_ptr is impossible, with or without Boost.

In C++03, there are a few possible alternatives, although each have their flaws.

  • boost::shared_ptr is probably the simplest replacement in terms of capabilites. You can safely use it anywhere you'd otherwise use a unique_ptr and it'd work. It just wouldn't be as efficient, because of the added reference counting. But if you're looking for a simple drop-in replacement that's able to handle everything unique_ptr can do, this is probably your best bet. (Of course, a shared_ptr can do a lot more as well, but it can also simply be used as a drop-in replacement for unique_ptr.)
  • boost::scoped_ptr is similar to unique_ptr but does not allow transfer of ownership. It works great as long as the smart pointer is meant to retain exclusive ownership throughout its lifetime.
  • std::auto_ptr works very similar to unique_ptr, but has a few limitations, mainly that it can not be stored in standard library containers. If you're simply looking for a pointer that allows transfer of ownership, but which is not meant to be stored in containers or copied around, this is probably a good bet.
jalf
  • 243,077
  • 51
  • 345
  • 550
  • 4
    +1 for `auto_ptr` - since `unique_ptr` will not compile in the [places that auto_ptr causes bugs](http://stackoverflow.com/questions/111478/why-is-it-wrong-to-use-stdauto-ptr-with-stl-containers), this is exactly what OP is looking for. – BlueRaja - Danny Pflughoeft Jun 01 '10 at 22:56
  • 4
    Howard Hinnant's unique_ptr for c++03 works pretty well considering r-value refs don't exist. – deft_code Jun 02 '10 at 15:14
  • This is not completely true, as Howard Hinnant's demonstrated using the its move semantics emulation that has been reviewed already on Boost. I hope that someone will take its implementation and include it on Boost soon. – Vicente Botet Escriba Jun 02 '10 at 21:22
  • He describes it as capturing "most of the behavior" of the "real" `unique_ptr`, but doesn't seem to describe exactly what the limitations are. Anyone know? I've never used it, but it looks like you're right, (most of) `unique_ptr` can be implemented in C++03. – jalf Feb 08 '11 at 14:12
  • 2
    boost::scoped_ptr is a bad alternative because it doesn't work with forward declarated classes. boost::shared_ptr is a bad alternative because it has significant overhead. – Gabriel Schreiber Feb 28 '12 at 09:47
  • 1
    @GabrielSchreiber: doesn't work with forward-declared classes? How so? Always worked fine for me – jalf Feb 28 '12 at 09:49
  • 1
    @jalf: Did some testing. Has to do with boost::checked_delete called by scoped_ptr desctructor. If you explicitly define a destructor (of the class aggregating the scoped_ptr) and the definition of the class contained by the scoped_ptr is visible there it's ok. If you rely on the default destructor and define the pointed-to class in a source file the definition is not visible when the default constructor is created by the compiler (compiling a different source file) and it doesn't compile. – Gabriel Schreiber Feb 28 '12 at 10:03
  • @jalf: But thanks. Before I did additional testing, I thought it isn't possible in general and now I know how to fix my code. – Gabriel Schreiber Feb 28 '12 at 10:04
  • yeah, it is a bit of a pain, and the error messages if you get it wrong aren't exactly helpful, but it is doable. :) Nevertheless, you're right that all the alternatives have drawbacks. That's why `unique_ptr` was added, after all. :) – jalf Feb 28 '12 at 10:09
  • 2
    Another drawback for `boost::scoped_ptr` is that it does not provide a customer deleter. – jamesdlin Jun 06 '13 at 23:29
  • 2
    As of now this answer is no longer invalid. See [my answer](http://stackoverflow.com/a/28193068/1776942) which describes `boost::movelib::unique_ptr` introduced in Boost 1.57. – Adam Romanek Feb 04 '15 at 12:14
38

Starting from Boost 1.57 there's an official unique_ptr implementation in Boost.Move library.

From the documentation:

(...) a drop-in replacement for std::unique_ptr, usable also from C++03 compilers.

The code is available in <boost/move/unique_ptr.hpp> header file and lives in boost::movelib namespace. Moreover, Boost.Move library provides make_unique() factory function in <boost/move/make_unique.hpp>, also in boost::movelib namespace.

Hence the example from the question could be implemented this way:

#include <boost/move/unique_ptr.hpp>

using boost::movelib::unique_ptr;

unique_ptr<Base> create_base()
{
    return unique_ptr<Base>(new Derived);
}

See a live example on Wandbox. Note that the code compiles fine with gcc 4.6.4 in C++98 mode (!).

What's interesting in boost::movelib::unique_ptr when applied to your case with base/derived classes, the implementation provides a compile-time check for the declaration of a virtual destructor in the base class. If you happen to omit it the code won't compile (click the "Run (...)" button to see the compiler error message).

One minor issue is that includes come from boost/move directory but the code lives in boost::movelib namespace (subtle difference but can be annoying).

See also a thread on boost mailing list for more details.

Thanks to Ion Gaztañaga for this absolutely unique and useful piece of code.

Adam Romanek
  • 1,809
  • 1
  • 19
  • 36
10

You might want to try Howard Hinnant's 'proof of concept' unique_ptr<> implementation for C++03 (disclaimer - I haven't):

One of his examples is returning a unique_ptr<int>:

unique_ptr<int> factory(int i)
{
    return unique_ptr<int>(new int(i));
}
sehe
  • 374,641
  • 47
  • 450
  • 633
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • I have used this in production code, it works pretty well. The only issue we has was calling `boost::make_shared`, for a `class` with a `unique_ptr` parameter. – deft_code Jun 02 '10 at 15:11
5

How about unique_ptr from the interprocess library?

fbrereto
  • 35,429
  • 19
  • 126
  • 178
  • Can that be returned from a function safely? I couldn't find anything about that (but maybe I'm just blind). Also, is it the "right" thing to use, given that it's in the interprocess library instead of the smart pointers library? – Clark Gaebel Jun 01 '10 at 21:39
  • @wowus: No. That relies on move semantics which are new in C++0x. That can't be simply emulated by boost -- that feature has to exist in the compiler itself. – Billy ONeal Jun 01 '10 at 21:41
  • Just looked, it needs r-value references. Therefore, not what I'm looking for. – Clark Gaebel Jun 01 '10 at 22:10
  • 7
    Interprocess unique_ptr has its own move emulation for C++03, that is the same as Boost.Move if I'm not wrong. – Vicente Botet Escriba Jun 02 '10 at 21:24
  • @Clark Gaebel, as indicated by Vincente in the comment above yes, the unique_ptr from Boost.Interprocess can be safely returned from a function via `boost::move()`. I've been using unique_ptr from Boost.Interprocess for like two yeas now with a lot of success. – Adam Romanek Jan 28 '15 at 12:52
4

I've used Howard Hinnant's unique_ptr. If you are not really good at reading crazy metaprogramming errors from you compiler you might want to steer clear. It however does act just like a unique_ptr in 90% of the cases.

Otherwise I'd suggest passing paramters as boost::scoped_ptr& and swap internally to steal ownership. To get unique_ptr style return values use an auto_ptr. Capture the auto_ptr return value in a shared_ptr or scoped_ptr to avoid using the auto_ptr directly.

deft_code
  • 57,255
  • 29
  • 141
  • 224