0

I'm having a problem with std::unique_ptr. I thought I understood them but clearly not.

I have the following code:

X::X() : m_foo(nullptr),
{
    m_foo = std::unique_ptr<Foo>(new Foo());
}

X::X(Foo* foo) : m_foo(nullptr),
{
    m_foo = std::unique_ptr<Foo>(foo);
}

std::unique_ptr<Foo> m_foo;

When I construct X as follows:

Foo foo;
X x(&foo);

I get an error at runtime telling me that 'error for object 0x101f7eec0: pointer being freed was not allocated'.

However, when I construct X as follows:

Foo foo;
X x;

no such error occurs.

If I add the following destructor:

X::~X()
{
    m_foo.release();
}

everything works OK.

I'm not really sure why the error occurs in the first place nor why releasing foo clears it.

Please can someone explain.

ksl
  • 4,519
  • 11
  • 65
  • 106
  • In addition to ComicSansMS's answer, you don't need to initialize `m_foo` to `nullptr` and then assign it a newly constructed `std::unique_ptr`. You can immediately initialize `m_foo` with the proper pointer, with `m_foo(new Foo())` and `m_foo(foo)` respectively. The whole point of explicit member initializers is avoiding the member-construction-followed-by-assignment antipattern. – user4815162342 Jul 11 '14 at 10:34

2 Answers2

4

std::unique_ptr is for managing lifetime of dynamically allocated objects (that is, objects created using new and the likes).

In your failing example, foo is created with automatic storage, so there is no need to manage its lifetime (and attempting to do so anyway will result in the error you observed). The compiler will automatically destroy it once it goes out of scope.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
  • Are you saying that I can't create a unique_ptr from a raw pointer? – ksl Jul 11 '14 at 10:28
  • @ksl You can, but doing so will transfer ownership of the pointer to the unique_ptr. As a consequence, the unique_ptr will attempt to call `delete` on the pointer (or invoke a custom deleter if specified) once you destroy the unique_ptr . – ComicSansMS Jul 11 '14 at 10:29
  • And you can't call delete on an object that was created on the stack - is that what you're getting at? So, by releasing foo in the destructor, you effectively tell the compiler not to call delete. Is that right? I also presume that would not cause a memory leak because the unique_ptr will be destroyed when X is destroyed and foo will be destroyed when the caller goes out of scope? – ksl Jul 11 '14 at 10:32
  • @ksl Yes, you do not want to call delete on an object that was not allocated with `new`. The point is, there is no need for `unique_ptr` in the first place if the object is allocated on the stack. Simply use a raw pointer or reference for passing it around. Only use `unique_ptr` if you want to imply ownership, that is, an object that is supposed to be deleted when the unique_ptr dies. – ComicSansMS Jul 11 '14 at 10:36
3

When you do this

Foo foo;
X x(&foo);

foo is allocated in the stack. Objects in stack cannot be included in unique_ptr. You only can do it if the object is in the heap:

Foo* foo = new Foo( );
X x( foo );
eferion
  • 872
  • 9
  • 14