CodeNebula
C++14stlintermediate

std::make_unique

C++14 · Modern Refined · Compiler flag: -std=c++14

Explanation

Creates a `std::unique_ptr` in a single expression, complementing `std::make_shared` from C++11. It eliminates the need for raw `new`, prevents memory leaks in expressions with multiple allocations, and makes ownership semantics explicit at the call site.

Real-World Scenario

A plugin system dynamically loads modules at startup. Each module is heap-allocated and owned by a unique pointer, ensuring automatic cleanup when the plugin manager shuts down.

Quick Snippet

snippet.cpp
#include <memory>
#include <iostream>

struct Sensor {
    std::string name;
    Sensor(std::string n) : name(std::move(n)) {
        std::cout << name << " initialized\n";
    }
    ~Sensor() { std::cout << name << " destroyed\n"; }
};

int main() {
    auto temp = std::make_unique<Sensor>("Thermocouple");
    auto accel = std::make_unique<Sensor>("Accelerometer");
    // automatic cleanup in reverse order
}

Full Example

make_unique.cpp
// CodeNebula - C++14 Example: std::make_unique
// Compile: g++ -std=c++14 -Wall -Wextra -o example make_unique.cpp

// Demonstrates std::make_unique for safe unique_ptr creation. This was a
// notable omission from C++11 (which had make_shared but not make_unique).
// Real-world use: exception-safe memory allocation, factory functions,
// avoiding raw 'new', and building ownership-clear APIs.

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

// ------------------------------------------------------------------
// Sample classes for demonstration
// ------------------------------------------------------------------
class Widget
{
    std::string name_;
    int value_;
public:
    Widget(std::string name, int value)
        : name_(std::move(name)), value_(value)
    {
        std::cout << "  Widget(" << name_ << ", " << value_ << ") constructed" << std::endl;
    }

    ~Widget() { std::cout << "  Widget(" << name_ << ") destroyed" << std::endl; }

    void show() const
    {
        std::cout << "  Widget: " << name_ << " = " << value_ << std::endl;
    }
};

class Base
{
public:
    virtual ~Base() = default;
    virtual std::string type() const { return "Base"; }
};

class Derived : public Base
{
public:
    std::string type() const override { return "Derived"; }
};

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic make_unique (replaces: unique_ptr<T>(new T(...)))
    // ------------------------------------------------------------------
    std::cout << "=== Basic make_unique ===" << std::endl;
    auto w1 = std::make_unique<Widget>("Alpha", 42);
    w1->show();
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. make_unique with no arguments (default construction)
    // ------------------------------------------------------------------
    std::cout << "=== Default Construction ===" << std::endl;
    auto num = std::make_unique<int>();       // value-initialized to 0
    auto str = std::make_unique<std::string>();
    std::cout << "  *num = " << *num << std::endl;
    std::cout << "  *str = \"" << *str << "\" (empty)" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. make_unique for arrays
    // ------------------------------------------------------------------
    std::cout << "=== Array make_unique ===" << std::endl;
    auto arr = std::make_unique<int[]>(5);    // array of 5 ints
    for (int i = 0; i < 5; ++i)
        arr[i] = (i + 1) * 10;
    std::cout << "  Array contents:";
    for (int i = 0; i < 5; ++i)
        std::cout << " " << arr[i];
    std::cout << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Polymorphism with make_unique
    // ------------------------------------------------------------------
    std::cout << "=== Polymorphic make_unique ===" << std::endl;
    std::unique_ptr<Base> base_ptr = std::make_unique<Derived>();
    std::cout << "  Type: " << base_ptr->type() << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. Storing in containers
    // ------------------------------------------------------------------
    std::cout << "=== Container of unique_ptrs ===" << std::endl;
    std::vector<std::unique_ptr<Widget>> widgets;
    widgets.push_back(std::make_unique<Widget>("Beta", 10));
    widgets.push_back(std::make_unique<Widget>("Gamma", 20));
    widgets.push_back(std::make_unique<Widget>("Delta", 30));

    std::cout << "  All widgets:" << std::endl;
    for (const auto& w : widgets)
        w->show();
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 6. Exception safety advantage
    // ------------------------------------------------------------------
    std::cout << "=== Exception Safety Note ===" << std::endl;
    std::cout << "  // Dangerous (C++11): may leak if second new throws" << std::endl;
    std::cout << "  // func(unique_ptr<A>(new A), unique_ptr<B>(new B));" << std::endl;
    std::cout << "  // Safe (C++14):" << std::endl;
    std::cout << "  // func(make_unique<A>(), make_unique<B>());" << std::endl;
    std::cout << std::endl;

    std::cout << "=== Automatic Cleanup ===" << std::endl;

    return 0;
}

/*
Expected output:

=== Basic make_unique ===
  Widget(Alpha, 42) constructed
  Widget: Alpha = 42

=== Default Construction ===
  *num = 0
  *str = "" (empty)

=== Array make_unique ===
  Array contents: 10 20 30 40 50

=== Polymorphic make_unique ===
  Type: Derived

=== Container of unique_ptrs ===
  Widget(Beta, 10) constructed
  Widget(Gamma, 20) constructed
  Widget(Delta, 30) constructed
  All widgets:
  Widget: Beta = 10
  Widget: Gamma = 20
  Widget: Delta = 30

=== Exception Safety Note ===
  // Dangerous (C++11): may leak if second new throws
  // func(unique_ptr<A>(new A), unique_ptr<B>(new B));
  // Safe (C++14):
  // func(make_unique<A>(), make_unique<B>());

=== Automatic Cleanup ===
  Widget(Delta) destroyed
  Widget(Gamma) destroyed
  Widget(Beta) destroyed
  Widget(Alpha) destroyed
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example make_unique.cpp