Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when redirecting unique_ptr?

I understand that unique_ptr is a single owner of some object and it deallocates that object when it goes out of scope. What I don't understand is the following situation:

unique_ptr<int> p(new int(1));
p = unique_ptr<int>(new int(2));

What happens with the first object new int(1) if p is redirected to another memory location new int(2) (since p can own only one of those)?

like image 409
Tracer Avatar asked Mar 08 '16 00:03

Tracer


People also ask

What happens when you move a unique_ptr?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it.

What does unique_ptr Reset do?

unique_ptr::resetReplaces the managed object. 1) Given current_ptr , the pointer that was managed by *this, performs the following actions, in this order: Saves a copy of the current pointer old_ptr = current_ptr. Overwrites the current pointer with the argument current_ptr = ptr.

What happens when unique_ptr goes out of scope?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

Does unique_ptr call Delete?

But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.


2 Answers

unique_ptr destroys the object it owns when the unique_ptr is destroyed or reseated. For example:

#include <iostream>
#include <memory>
using namespace std;

struct T {
    T(int x) : x(x) {
        cout << "T(" << x << ")\n";
    }
    ~T() {
        cout << "~T(" << x << ")\n";
    }
    int x;
};

int main() {
    unique_ptr<T> p(new T(1));
    p = unique_ptr<T>(new T(2));
}

This will print:

  • T(1) when the first object is created.
  • T(2) when the second object is created.
  • ~T(1) when the first object is freed by the assignment operator of p.
  • ~T(2) when the second object is freed by the destructor of p.
like image 89
Jon Purdy Avatar answered Sep 20 '22 22:09

Jon Purdy


unique_ptr is defined to make sure the first int is properly deallocated, so it calls a delete on it, freeing the reserved memory.

It is somewhat identical to this code:

int* p = new int(1);
delete p;
p = new int(2);

What happens in detail is this:

  • You create a new Integer using new int(1).
  • You pass the pointer to this new int to the just created instance of unique_ptr named p. This is an object that just stores the pointer for the moment.
  • You create a second int using new int(2).
  • You pass this pointer to a new unique_ptr using unique_ptr<int>(new int(2)), this is a temporary instance of unique_ptr (we will see why in a second) and it stores the pointer to the second int.
  • You assign the temporary object to p. Now the assignment operator is defined to delete the previously owned object (the first int) and take ownership of the object owned by the assigned unique_ptr (the second int). An implementation is shown below. At this point p owns the second int, the first int is deleted and the temporary owns no object anymore (holding the nullptr).
  • As last part the temporary unique_ptr goes out of scope, since we never gave it a name or stored a reference to it, so its destructor gets called. But it only holds the nullptr anyway.

So the more detailed equivalent using raw pointers would be something like this:

int* p = new int(1);  //create an int
{
    int* tmp = new int(2);  //create second int
    int* del = p; //we need to delete this (first int)

    //take ownership of the temporary (second int)
    p = tmp; 
    tmp=nullptr;

    //delete the old object (first int)
    delete del;
}  //tmp and del go out of scope here, but tmp holds the nullptr and del is deleted
//first int is deleted, p points to the second int here

Edit for Tracer: This is the implementation used by visual studio (the comment is part of <memory> as well):

typedef unique_ptr<_Ty> _Myt;

_Myt& operator=(_Myt&& _Right) _NOEXCEPT
{   // assign by moving _Right
    if (this != &_Right)
    {   // different, do the move
        reset(_Right.release());
        this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
    }
return (*this);
}

void reset(pointer _Ptr = pointer()) _NOEXCEPT
 {  // establish new pointer
    pointer _Old = get();
    this->_Myptr() = _Ptr;
    if (_Old != pointer())
        this->get_deleter()(_Old);
 }
like image 27
Anedar Avatar answered Sep 17 '22 22:09

Anedar