๐ŸŽ“ A1Learner
๐Ÿ”
0 of 34 lessons completed

C++ Unique Pointers

A unique pointer is a smart pointer that owns an object on its own. The owned object is deleted automatically when the pointer leaves scope.

An owned object deletes itself at scope end

std::make_unique builds a Message and the pointer calls its method. The destructor line prints when the pointer leaves scope, with no delete line anywhere.

#include <iostream>
#include <memory>

class Message {
public:
  void print() {
    std::cout << "Hello from the object\n";
  }
  ~Message() {
    std::cout << "Message deleted\n";
  }
};

int main() {
  {
    auto ptr = std::make_unique<Message>();
    ptr->print();
    std::cout << "Leaving the scope\n";
  }
  std::cout << "Scope ended\n";
  return 0;
}

Moving transfers the value

std::move hands the owned value from the first pointer to the second. The source tests empty and the target prints the value.

#include <iostream>
#include <memory>

int main() {
  std::cout << std::boolalpha;
  auto first = std::make_unique<int>(42);
  auto second = std::move(first);
  std::cout << "Source empty: " << (first == nullptr) << "\n";
  std::cout << "Target value: " << *second << "\n";
  return 0;
}

Copying a unique pointer is refused

This program tries to copy a unique pointer into a second pointer. The compiler refuses the program and reports the error line below.

#include <iostream>
#include <memory>

int main() {
  auto first = std::make_unique<int>(42);
  auto second = first;
  std::cout << *second << "\n";
  return 0;
}

reset drops early and get reads

reset deletes the first Value in the middle of the scope and stores a fresh one. get then reads the new value without taking ownership away.

#include <iostream>
#include <memory>

class Value {
public:
  int number;
  Value(int n) {
    number = n;
  }
  void print() {
    std::cout << "Value: " << number << "\n";
  }
  ~Value() {
    std::cout << "Value deleted\n";
  }
};

int main() {
  {
    auto ptr = std::make_unique<Value>(10);
    ptr->print();
    ptr.reset(new Value(20));
    std::cout << "Via get: " << ptr.get()->number << "\n";
    std::cout << "Still in scope\n";
  }
  std::cout << "Scope ended\n";
  return 0;
}

Example

#include <iostream>
#include <memory>

class Report {
public:
  int pages;
  Report(int count) {
    pages = count;
  }
  void print() {
    std::cout << "Report pages: " << pages << "\n";
  }
  ~Report() {
    std::cout << "Report deleted\n";
  }
};

void showReport(std::unique_ptr<Report> report) {
  report->print();
  std::cout << "Function ending\n";
}

int main() {
  auto ptr = std::make_unique<Report>(12);
  showReport(std::move(ptr));
  std::cout << "Back in main\n";
  return 0;
}

Key points

  • The <memory> header provides std::unique_ptr and std::make_unique.
  • std::make_unique builds an object and returns the unique pointer that owns it.
  • A unique pointer has exactly one owner at any time.
  • Copying a unique pointer is refused by the compiler.
  • std::move transfers ownership and leaves the source empty.
  • reset deletes the owned object at once.
  • get gives access to the owned object without giving up ownership.

In this example, main builds a Report with 12 pages and moves its unique pointer into showReport. The function prints the page count through the pointer. The pointer owns the Report until the function ends, so the deletion line prints before main prints its last line.

Note

No delete line appears in code that owns an object through a unique pointer.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What happens when a unique pointer is passed with std::move?