C++11coreintermediate
std::unique_ptr (C++11 Addition)
C++11 · Modern Revolution · Compiler flag: -std=c++11
Explanation
Smart pointer with single ownership semantics, replacing `std::auto_ptr`.
Real-World Scenario
Manage a unique resource in a system without leaks.
Quick Snippet
snippet.cpp
#include <memory> std::unique_ptr<int> ptr = std::make_unique<int>(5);Full Example
unique_ptr.cpp
// CodeNebula - C++11 Example: std::unique_ptr
// Compile: g++ -std=c++11 -Wall -Wextra -o example unique_ptr.cpp
//
// This example demonstrates:
// - std::unique_ptr for exclusive ownership of heap objects
// - Automatic cleanup when unique_ptr goes out of scope
// - std::move to transfer ownership
// - unique_ptr with arrays
// - Custom deleters
// - unique_ptr in containers and as function return values
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// ============================================================
// 1. Trackable resource
// ============================================================
class Widget {
std::string name_;
int id_;
public:
Widget(const std::string& name, int id) : name_(name), id_(id) {
std::cout << " Widget(" << name_ << ", " << id_ << ") created" << std::endl;
}
~Widget() {
std::cout << " Widget(" << name_ << ", " << id_ << ") destroyed" << std::endl;
}
void doWork() const {
std::cout << " Widget " << name_ << " working (id=" << id_ << ")" << std::endl;
}
};
// ============================================================
// 2. Factory function returning unique_ptr
// ============================================================
std::unique_ptr<Widget> createWidget(const std::string& name, int id) {
return std::unique_ptr<Widget>(new Widget(name, id));
// In C++14, use: return std::make_unique<Widget>(name, id);
}
// ============================================================
// 3. Function taking ownership via unique_ptr
// ============================================================
void consumeWidget(std::unique_ptr<Widget> w) {
std::cout << " consumeWidget: took ownership" << std::endl;
w->doWork();
// Widget destroyed when function returns
}
// ============================================================
// 4. Polymorphism with unique_ptr
// ============================================================
class Shape {
public:
virtual ~Shape() {}
virtual void draw() const = 0;
};
class Circle : public Shape {
double radius_;
public:
Circle(double r) : radius_(r) {}
void draw() const override {
std::cout << " Drawing circle (r=" << radius_ << ")" << std::endl;
}
};
class Square : public Shape {
double side_;
public:
Square(double s) : side_(s) {}
void draw() const override {
std::cout << " Drawing square (s=" << side_ << ")" << std::endl;
}
};
int main() {
std::cout << "=== std::unique_ptr ===" << std::endl;
// Basic creation and automatic cleanup
std::cout << "\n--- Basic usage ---" << std::endl;
{
std::unique_ptr<Widget> w(new Widget("Basic", 1));
w->doWork();
// Automatically destroyed at end of scope
}
// Factory function
std::cout << "\n--- Factory function ---" << std::endl;
{
auto w = createWidget("Factory", 2);
w->doWork();
}
// Transfer ownership with std::move
std::cout << "\n--- Move semantics ---" << std::endl;
{
auto w1 = createWidget("Movable", 3);
std::cout << " w1 valid: " << (w1 ? "yes" : "no") << std::endl;
std::unique_ptr<Widget> w2 = std::move(w1);
std::cout << " After move: w1 valid: " << (w1 ? "yes" : "no") << std::endl;
std::cout << " After move: w2 valid: " << (w2 ? "yes" : "no") << std::endl;
w2->doWork();
}
// Transfer to function (consuming)
std::cout << "\n--- Transfer to function ---" << std::endl;
{
auto w = createWidget("Consumed", 4);
consumeWidget(std::move(w));
std::cout << " After consume: w valid: " << (w ? "yes" : "no") << std::endl;
}
// unique_ptr with arrays
std::cout << "\n--- Array unique_ptr ---" << std::endl;
{
std::unique_ptr<int[]> arr(new int[5]);
for (int i = 0; i < 5; ++i) {
arr[i] = i * 10;
}
std::cout << " Array: ";
for (int i = 0; i < 5; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
// Container of unique_ptrs (polymorphism)
std::cout << "\n--- Container of unique_ptr (polymorphism) ---" << std::endl;
{
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::unique_ptr<Shape>(new Circle(5.0)));
shapes.push_back(std::unique_ptr<Shape>(new Square(3.0)));
shapes.push_back(std::unique_ptr<Shape>(new Circle(1.5)));
for (const auto& s : shapes) {
s->draw();
}
}
// Release and reset
std::cout << "\n--- release() and reset() ---" << std::endl;
{
auto w = createWidget("Released", 5);
Widget* raw = w.release(); // Give up ownership
std::cout << " After release: w valid: " << (w ? "yes" : "no") << std::endl;
raw->doWork();
delete raw; // Must manually delete now
auto w2 = createWidget("Resetable", 6);
w2.reset(); // Explicitly destroy
std::cout << " After reset: w2 valid: " << (w2 ? "yes" : "no") << std::endl;
}
return 0;
}
// Expected output:
// === std::unique_ptr ===
//
// --- Basic usage ---
// Widget(Basic, 1) created
// Widget Basic working (id=1)
// Widget(Basic, 1) destroyed
//
// --- Factory function ---
// Widget(Factory, 2) created
// Widget Factory working (id=2)
// Widget(Factory, 2) destroyed
//
// --- Move semantics ---
// Widget(Movable, 3) created
// w1 valid: yes
// After move: w1 valid: no
// After move: w2 valid: yes
// Widget Movable working (id=3)
// Widget(Movable, 3) destroyed
//
// --- Transfer to function ---
// Widget(Consumed, 4) created
// consumeWidget: took ownership
// Widget Consumed working (id=4)
// Widget(Consumed, 4) destroyed
// After consume: w valid: no
//
// --- Array unique_ptr ---
// Array: 0 10 20 30 40
//
// --- Container of unique_ptr (polymorphism) ---
// Drawing circle (r=5)
// Drawing square (s=3)
// Drawing circle (r=1.5)
//
// --- release() and reset() ---
// Widget(Released, 5) created
// After release: w valid: no
// Widget Released working (id=5)
// Widget(Released, 5) destroyed
// Widget(Resetable, 6) created
// Widget(Resetable, 6) destroyed
// After reset: w2 valid: no
Run command
g++ -std=c++11 -Wall -Wextra -o example unique_ptr.cpp