如何:创建和使用 unique_ptr 实例

unique_ptr不共享其指针。 它不能复制到另一个 unique_ptr函数,由值传递给函数,也不能在任何需要复制副本的 C++ 标准库算法中使用。 只能移动 unique_ptr。 这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。 建议将对象限制为一个所有者,因为多个所有权增加了复杂性。 当您需要为一个纯 C++ 对象使用智能指针时,请使用unique_ptr;当您构造unique_ptr时,请使用make_unique辅助函数。

下图演示了两个 unique_ptr 实例之间的所有权转换。

显示移动唯一指针所有权的示意图。

unique_ptr 在 C++ 标准库的 <memory> 标头中定义。 它与原始指针一样高效,可在 C++ 标准库容器中使用。 将 unique_ptr 实例添加到 C++ 标准库容器很有效,因为通过 unique_ptr 的移动构造函数,不再需要进行复制操作。

若要使用 unique_ptrmake_unique,请包含 <memory> 标头。 以下示例每个编译并作为独立程序运行。

示例 1

以下示例演示如何创建 unique_ptr 实例并在函数之间传递这些实例。 通过按值返回 unique_ptr 将所有权转让给调用方。 将 unique_ptr 按值传递给函数会将所有权传递给调用方。

// Compile with: cl /EHsc /std:c++17

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

struct Song {
    std::string artist;
    std::string title;
    Song(const std::string& a, const std::string& t) : artist(a), title(t) {
        std::cout << "Created: " << title << "\n";
    }
    ~Song() { std::cout << "Destroyed: " << title << "\n"; }
};

// Returning a unique_ptr by value transfers ownership to the caller.
std::unique_ptr<Song> SongFactory(const std::string& artist, const std::string& title) {
    return std::make_unique<Song>(artist, title);
}

// Passing a unique_ptr by value transfers ownership to the function.
// The Song is automatically destroyed when the function exits.
void SingSong(std::unique_ptr<Song> song) {
    std::cout << "Singing: " << song->title << " by " << song->artist << "\n";
}

int main() {
    // Create a new unique_ptr with a new object.
    auto song = std::make_unique<Song>("Mr. Children", "Namonaki Uta");
    std::cout << "song points to: " << song->title << "\n";

    // Move ownership from one unique_ptr to another.
    std::unique_ptr<Song> song2 = std::move(song);
    std::cout << "After move, song is " << (song ? "not null" : "null") << "\n";
    std::cout << "song2 points to: " << song2->title << "\n";

    // Obtain unique_ptr from a factory function that returns by value.
    auto song3 = SongFactory("Michael Jackson", "Beat It");

    // Transfer ownership to a function.
    SingSong(std::move(song3));
    std::cout << "After SingSong, song3 is " << (song3 ? "not null" : "null") << "\n";
}
Created: Namonaki Uta
song points to: Namonaki Uta
After move, song is null
song2 points to: Namonaki Uta
Created: Beat It
Singing: Beat It by Michael Jackson
Destroyed: Beat It
After SingSong, song3 is null
Destroyed: Namonaki Uta

这些示例说明了 unique_ptr 的基本特征:可移动,但不可复制。 “移动”将所有权转移到新 unique_ptr 并重置旧 unique_ptr

示例 2

以下示例演示如何创建 unique_ptr 实例并在向量中使用这些实例。

// Compile with: cl /EHsc /std:c++17

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

struct Song {
    std::string artist;
    std::string title;
    Song(const std::string& a, const std::string& t) : artist(a), title(t) {}
};

int main() {
    std::vector<std::unique_ptr<Song>> songs;

    // Create unique_ptr<Song> instances and add them to the vector
    // using implicit move semantics.
    songs.push_back(std::make_unique<Song>("B'z", "Juice"));
    songs.push_back(std::make_unique<Song>("Namie Amuro", "Funky Town"));
    songs.push_back(std::make_unique<Song>("Kome Kome Club", "Kimi ga Iru Dake de"));
    songs.push_back(std::make_unique<Song>("Ayumi Hamasaki", "Poker Face"));

    // Pass by const reference to avoid copying.
    // Passing by value causes a compile error because
    // the unique_ptr copy constructor is deleted.
    for (const auto& song : songs) {
        std::cout << "Artist: " << song->artist
                  << "   Title: " << song->title << "\n";
    }
    // The unique_ptr instances in the vector are automatically destroyed when the vector goes out of scope at the end of main()
}
Artist: B'z   Title: Juice
Artist: Namie Amuro   Title: Funky Town
Artist: Kome Kome Club   Title: Kimi ga Iru Dake de
Artist: Ayumi Hamasaki   Title: Poker Face
Destroyed: Juice
Destroyed: Funky Town
Destroyed: Kimi ga Iru Dake de
Destroyed: Poker Face

在 range for 循环中,注意 unique_ptr 通过引用来传递。 如果尝试在此处传递值,编译器会报告错误,因为 unique_ptr 复制构造函数已删除。

示例 3

以下示例演示如何初始化类成员 unique_ptr

// Compile with: cl /EHsc /std:c++17

#include <iostream>
#include <memory>

class Engine {
public:
    Engine() { std::cout << "Engine created\n"; }
    ~Engine() { std::cout << "Engine destroyed\n"; }
    void Run() { std::cout << "Engine running\n"; }
};

class Car {
private:
    // Car owns the unique_ptr.
    std::unique_ptr<Engine> engine;
public:
    // Initialize by using make_unique in the member initializer list.
    Car() : engine(std::make_unique<Engine>()) {}

    void Start() {
        engine->Run();
    }
};

int main() {
    Car car;
    car.Start();
}
Engine created
Engine running
Engine destroyed

示例 4

可以使用 make_unique 创建 unique_ptr 数组。 make_unique<int[]>(5) 创建一个值初始化为零的五个元素数组。 不能将 make_unique单个元素值传递到其中,因此在创建后对其进行分配。

// Compile with: cl /EHsc /std:c++17

#include <iostream>
#include <memory>

int main() {
    // Create a unique_ptr to an array of 5 integers.
    // The elements are value-initialized to 0.
    auto p = std::make_unique<int[]>(5);

    // Assign values to the array elements.
    for (int i = 0; i < 5; ++i) {
        p[i] = i;
        std::cout << p[i] << "\n";
    }
    // The array is automatically deleted when p goes out of scope.
}
0
1
2
3
4

有关更多示例,请参阅 make_unique

另请参阅

智能指针(现代 C++)
make_unique