Cppunique_ptr

unique_ptr

std::unique_ptr, from the <memory> header, is the default smart pointer for owning a heap-allocated object. It expresses exclusive ownership: at any given moment, exactly one unique_ptr owns a particular object, and when that unique_ptr is destroyed, the object is automatically deleted with it. There is essentially no runtime overhead compared to a raw pointer, which is why it should be your default choice.
Creating a unique_ptr

unique_ptr_basics.cpp

CPP
#include <memory>
#include <iostream>

struct Widget {
    int id;
    Widget(int id) : id(id) { std::cout << "Widget " << id << " created" << std::endl; }
    ~Widget() { std::cout << "Widget " << id << " destroyed" << std::endl; }
};

int main() {
    std::unique_ptr<Widget> w = std::make_unique<Widget>(1);

    std::cout << "Using widget " << w->id << std::endl;

    return 0;
}   // w goes out of scope here -> destructor runs automatically -> "Widget 1 destroyed"
Accessing the underlying object
A unique_ptr behaves like a raw pointer for the purposes of accessing the object it owns: use -> to call a member, and * to dereference it directly.

unique_ptr_access.cpp

CPP
auto w = std::make_unique<Widget>(2);

std::cout << w->id << std::endl;   // member access via ->
Widget& ref = *w;                    // dereference to get the object itself
std::cout << ref.id << std::endl;

int* raw = nullptr;                  // just for contrast — not related to w
(void)raw;
Move-only: unique_ptr cannot be copied
Because ownership must always stay exclusive, unique_ptr deletes its copy constructor and copy assignment operator. Trying to copy one is a compile error, not a runtime surprise. To transfer ownership from one unique_ptr to another, you must explicitly move it, which leaves the original empty (holding nullptr).
Copying a unique_ptr is a compile error

unique_ptr_copy_error.cpp

CPP
std::unique_ptr<Widget> a = std::make_unique<Widget>(3);
std::unique_ptr<Widget> b = a;   // COMPILE ERROR: use of deleted function
                                   // 'std::unique_ptr<Widget>::unique_ptr(const std::unique_ptr<Widget>&)'
The fix is to move ownership instead of copying it, using std::move:

unique_ptr_move.cpp

CPP
#include <memory>
#include <iostream>
#include <utility>

int main() {
    std::unique_ptr<Widget> a = std::make_unique<Widget>(4);
    std::unique_ptr<Widget> b = std::move(a);   // ownership transfers to b

    if (a == nullptr) {
        std::cout << "a no longer owns anything" << std::endl;
    }
    std::cout << "b now owns widget " << b->id << std::endl;

    return 0;
}
get(), release(), and reset()

Three member functions give you lower-level control when you need to interoperate with raw-pointer APIs:

  • .get() returns the raw pointer WITHOUT giving up ownership — the unique_ptr still owns and will still delete it.

  • .release() gives up ownership and returns the raw pointer — you are now responsible for deleting it yourself.

  • .reset() destroys the currently owned object (if any) and optionally takes ownership of a new one.

unique_ptr_get_release_reset.cpp

CPP
auto w = std::make_unique<Widget>(5);

Widget* raw = w.get();     // look, but don't take ownership
std::cout << raw->id << std::endl;

w.reset();                    // destroys widget 5 immediately, w is now empty
w.reset(new Widget(6));       // takes ownership of a new widget

Widget* released = w.release();  // w gives up ownership; w is now empty
// you must now manually delete 'released' — it's a plain raw pointer again
delete released;
Rule of thumb
Use .get() when a function needs a raw pointer just to look at the object (e.g. a C API), and only use .release() when you genuinely need to hand off ownership to code that expects to manage the raw pointer itself. Most code never needs either.