Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. C++ Dictionary
  3. std::unique_ptr

std::unique_ptr

In C++, unique_ptr is a smart pointer that manages exclusive ownership of dynamically allocated memory. Only one object can hold ownership at a time, and memory is automatically released when the pointer goes out of scope. Manual delete is not needed, making it widely used to prevent memory leaks.

Syntax

// ========================================
// Basic syntax for unique_ptr
// ========================================
#include <memory>

// Create an object with make_unique (available since C++14)
std::unique_ptr<Type> ptr = std::make_unique<Type>(constructor_args);

// Can be used just like a pointer
ptr->memberFunction();
*ptr;  // dereference

// Transfer ownership to another unique_ptr (copying is forbidden)
std::unique_ptr<Type> ptr2 = std::move(ptr);
// ptr becomes nullptr after this

// Get the raw pointer (ownership is not transferred)
Type* raw = ptr2.get();

// Explicitly reset (releases managed object and sets to nullptr)
ptr2.reset();

// Using a custom deleter
auto deleter = [](Type* p) { delete p; };
std::unique_ptr<Type, decltype(deleter)> ptr3(new Type(), deleter);

Syntax Reference

Syntax / OperationDescription
std::make_unique<T>(...)Dynamically allocates an object of type T and returns a unique_ptr. Available since C++14.
std::unique_ptr<T> p(new T(...))Constructs a unique_ptr from a raw pointer. Used when make_unique is not available.
p->member / *pAccesses members of the managed object. Works just like a regular pointer.
std::move(p)Transfers ownership to another unique_ptr. Since copying is forbidden, move is required.
p.get()Returns the managed raw pointer. Ownership is not transferred.
p.reset()Releases the managed object and sets to nullptr. A new pointer can be passed as an argument to replace it.
p.release()Releases ownership and returns the raw pointer. Responsibility for deallocation moves to the caller.
if (p)Evaluates to true if not nullptr. Can be used for null checks.

Sample Code

steinsgate_unique_ptr.cpp
// ========================================
// steinsgate_unique_ptr.cpp
// Manages Steins;Gate lab members with unique_ptr,
// demonstrating ownership transfer, reset, and null checks
// ========================================

#include <iostream>
#include <memory>
#include <string>
#include <vector>

// ========================================
// LabMember class (Future Gadget Lab member)
// ========================================
class LabMember {
private:
    std::string name;      // member name
    int memberNumber;      // lab member number
    std::string nickname;  // nickname

public:
    LabMember(const std::string& name, int memberNumber, const std::string& nickname)
        : name(name), memberNumber(memberNumber), nickname(nickname) {
        std::cout << "[Alloc] Lab member #" << memberNumber << " " << name << " allocated." << std::endl;
    }

    ~LabMember() {
        std::cout << "[Free]  Lab member #" << memberNumber << " " << name << " freed." << std::endl;
    }

    void introduce() const {
        std::cout << "Lab member #" << memberNumber << ": " << name
                  << " (" << nickname << ")" << std::endl;
    }

    const std::string& getName() const { return name; }
    int getMemberNumber() const { return memberNumber; }
};

// ========================================
// Takes a unique_ptr by value (ownership transfers, move required)
// ========================================
void assignToTimeMachine(std::unique_ptr<LabMember> member) {
    std::cout << "  Assigning " << member->getName() << " to the time machine." << std::endl;
    // member is destroyed when the function exits, releasing memory
}

// ========================================
// Takes a unique_ptr by const reference (ownership stays)
// ========================================
void printMember(const std::unique_ptr<LabMember>& member) {
    if (member) {
        member->introduce();
    } else {
        std::cout << "  (This slot is empty)" << std::endl;
    }
}

int main() {
    std::cout << "=== unique_ptr Basic Operations ===" << std::endl << std::endl;

    // ----------------------------------------
    // Create objects with make_unique
    // ----------------------------------------
    std::unique_ptr<LabMember> okabe = std::make_unique<LabMember>(
        "Okabe Rintaro", 1, "Hououin Kyouma"
    );
    std::unique_ptr<LabMember> kurisu = std::make_unique<LabMember>(
        "Makise Kurisu", 4, "Christina"
    );

    std::cout << std::endl;
    std::cout << "--- Introductions ---" << std::endl;
    printMember(okabe);
    printMember(kurisu);

    // ----------------------------------------
    // get() retrieves the raw pointer (no ownership transfer)
    // ----------------------------------------
    std::cout << std::endl << "--- get(): access raw pointer ---" << std::endl;
    LabMember* rawPtr = okabe.get();
    std::cout << "  via rawPtr: ";
    rawPtr->introduce();
    std::cout << "  okabe still valid: " << (okabe ? "true" : "false") << std::endl;

    // ----------------------------------------
    // move() transfers ownership
    // ----------------------------------------
    std::cout << std::endl << "--- move(): transfer ownership ---" << std::endl;
    std::unique_ptr<LabMember> newOwner = std::move(okabe);
    std::cout << "  okabe valid: " << (okabe ? "true" : "false") << std::endl;
    std::cout << "  newOwner inherited: ";
    newOwner->introduce();

    // ----------------------------------------
    // Pass ownership to a function via move
    // ----------------------------------------
    std::cout << std::endl << "--- pass to function via move ---" << std::endl;
    assignToTimeMachine(std::move(newOwner));
    std::cout << "  newOwner valid: " << (newOwner ? "true" : "false") << std::endl;

    // ----------------------------------------
    // reset() releases and replaces the managed object
    // ----------------------------------------
    std::cout << std::endl << "--- reset(): replace managed object ---" << std::endl;
    std::cout << "  Resetting kurisu, replacing with Shiina Mayuri." << std::endl;
    kurisu.reset(new LabMember("Shiina Mayuri", 2, "Mayushii"));
    printMember(kurisu);

    // ----------------------------------------
    // release() gives up ownership
    // ----------------------------------------
    std::cout << std::endl << "--- release(): give up ownership ---" << std::endl;
    LabMember* released = kurisu.release();
    std::cout << "  kurisu valid: " << (kurisu ? "true" : "false") << std::endl;
    std::cout << "  via released: ";
    released->introduce();
    // Manual delete required after release()
    delete released;

    // ----------------------------------------
    // vector manages multiple unique_ptrs
    // ----------------------------------------
    std::cout << std::endl << "--- vector<unique_ptr> management ---" << std::endl;
    std::vector<std::unique_ptr<LabMember>> labMembers;
    labMembers.push_back(std::make_unique<LabMember>("Amane Suzuha", 7, "Part-time warrior"));
    labMembers.push_back(std::make_unique<LabMember>("Hashida Itaru", 3, "Daru"));

    std::cout << std::endl;
    std::cout << "  Lab member list:" << std::endl;
    for (int i = 0; i < (int)labMembers.size(); i++) {
        std::cout << "  ";
        printMember(labMembers[i]);
    }

    std::cout << std::endl << "--- main ending. All members auto-freed when vector is destroyed ---" << std::endl;
    return 0;
}
# Compile
g++ -std=c++14 steinsgate_unique_ptr.cpp -o steinsgate_unique_ptr && ./steinsgate_unique_ptr
[Alloc] Lab member #1 Okabe Rintaro allocated.
[Alloc] Lab member #4 Makise Kurisu allocated.

--- Introductions ---
Lab member #1: Okabe Rintaro (Hououin Kyouma)
Lab member #4: Makise Kurisu (Christina)

--- get(): access raw pointer ---
  via rawPtr: Lab member #1: Okabe Rintaro (Hououin Kyouma)
  okabe still valid: true

--- move(): transfer ownership ---
  okabe valid: false
  newOwner inherited: Lab member #1: Okabe Rintaro (Hououin Kyouma)

--- pass to function via move ---
  Assigning Okabe Rintaro to the time machine.
[Free]  Lab member #1 Okabe Rintaro freed.
  newOwner valid: false

--- reset(): replace managed object ---
  Resetting kurisu, replacing with Shiina Mayuri.
[Free]  Lab member #4 Makise Kurisu freed.
[Alloc] Lab member #2 Shiina Mayuri allocated.
Lab member #2: Shiina Mayuri (Mayushii)

--- release(): give up ownership ---
  kurisu valid: false
  via released: Lab member #2: Shiina Mayuri (Mayushii)
[Free]  Lab member #2 Shiina Mayuri freed.

--- vector<unique_ptr> management ---
[Alloc] Lab member #7 Amane Suzuha allocated.
[Alloc] Lab member #3 Hashida Itaru allocated.

  Lab member list:
  Lab member #7: Amane Suzuha (Part-time warrior)
  Lab member #3: Hashida Itaru (Daru)

--- main ending. All members auto-freed when vector is destroyed ---
[Free]  Lab member #7 Amane Suzuha freed.
[Free]  Lab member #3 Hashida Itaru freed.

Common Mistakes

Copying a unique_ptr causes a compile error. unique_ptr has its copy constructor and copy assignment operator deleted to guarantee exclusive ownership. To transfer it to another variable, you must use std::move() to transfer ownership.

copy_error_ng.cpp — NG: causes a compile error
#include <memory>
#include <string>

int main() {
    std::unique_ptr<std::string> p1 = std::make_unique<std::string>("Okabe Rintaro");

    // Copying causes a compile error
    std::unique_ptr<std::string> p2 = p1;  // error: use of deleted function

    return 0;
}
copy_ok.cpp — OK: use move to transfer ownership
#include <memory>
#include <string>

int main() {
    std::unique_ptr<std::string> p1 = std::make_unique<std::string>("Okabe Rintaro");

    // Use move to transfer ownership
    std::unique_ptr<std::string> p2 = std::move(p1);
    // p1 becomes nullptr after this

    return 0;
}

Using unique_ptr<T[]> for arrays. When managing a dynamically allocated array, use unique_ptr<T[]>. The array version automatically calls delete[]. Use make_unique<T[N]> (C++14 and later) to specify the number of elements. All elements are automatically freed when the pointer goes out of scope.

array_unique_ptr.cpp
#include <iostream>
#include <memory>
#include <string>

int main() {
    // Create array unique_ptr with make_unique (C++14 and later)
    // Specify element count with make_unique<T[N]>
    std::unique_ptr<std::string[]> labMembers = std::make_unique<std::string[]>(5);

    // Access elements with subscript operator
    labMembers[0] = "Okabe Rintaro";
    labMembers[1] = "Makise Kurisu";
    labMembers[2] = "Shiina Mayuri";
    labMembers[3] = "Hashida Itaru";
    labMembers[4] = "Amane Suzuha";

    std::cout << "=== Future Gadget Lab Members ===" << std::endl;
    for (int i = 0; i < 5; i++) {
        std::cout << "  Lab member #" << (i + 1) << ": " << labMembers[i] << std::endl;
    }
    // delete[] is called automatically when scope exits

    return 0;
}
# Compile
g++ -std=c++14 array_unique_ptr.cpp -o array_unique_ptr && ./array_unique_ptr
=== Future Gadget Lab Members ===
  Lab member #1: Okabe Rintaro
  Lab member #2: Makise Kurisu
  Lab member #3: Shiina Mayuri
  Lab member #4: Hashida Itaru
  Lab member #5: Amane Suzuha

Overview

std::unique_ptr is a smart pointer that manages exclusive ownership of a dynamically allocated object. Only one unique_ptr holds ownership at any time, and when it goes out of scope, delete is automatically called to release memory. Copying is forbidden; to transfer ownership to another variable, use std::move(). After moving, the original pointer becomes nullptr. get() lets you retrieve the raw pointer to pass to legacy APIs, but note that ownership is not transferred. reset() can release the managed object or replace it with a different one. release() gives up ownership and returns the raw pointer, but since deallocation responsibility moves to the caller, its use cases are limited. Combining with std::vector lets you safely manage multiple objects, all of which are automatically freed when the vector is destroyed. When shared ownership is needed, consider shared_ptr.

If you find any errors or copyright issues, please .