Menu
Coddy logo textTech

C++ のスマートポインタ

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 15/104。

スマートポインタは、ヒープメモリを自動的に管理するラッパークラスです。ポインタがスコープ外になったときにメモリをクリーンアップすることで、手動での delete 呼び出しの必要性をなくします。

スマートポインタを使用するには、<memory>ヘッダーをインクルードしてください。

unique_ptr - 独占的な所有権。一度に一つのポインタのみがリソースを所有できます。

#include <memory>

std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack();  // 通常のポインタのように使用します

// コピーはできませんが、所有権を移譲することはできます
std::unique_ptr<Player> player2 = std::move(player);
// player は nullptr になります

shared_ptr - 共有所有権。複数のポインタが同じリソースを所有できます。最後の所有者が破棄されたときにメモリが解放されます。

std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1;  // 両方がリソースを所有しています

std::cout << p1.use_count();  // 2を出力します

weak_ptr - shared_ptr の所有権を持たないオブザーバーです。循環参照を解決するのに役立ちます。

std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;

if (auto locked = weak.lock()) {  // shared_ptrに変換
    locked->attack();
}

単一の所有権には、デフォルトで unique_ptr を使用します。複数のオブジェクトがリソースを共有する必要がある場合は、shared_ptr を使用します。生存期間を延長せずに監視するには、weak_ptr を使用します。

生の new よりも make_uniquemake_shared を優先してください。

challenge icon

チャレンジ

簡単

スマートポインタのさまざまな所有権モデルを実証するドキュメント共有システムを構築しましょう。unique_ptr がどのように排他的所有権を強制するか、shared_ptr がどのように複数の所有者を許可するか、そして weak_ptr が寿命に影響を与えずにどのように監視できるかを確認します。

コードを整理するために、2つのファイルを作成します。

  • Document.h: 共有可能なドキュメントを表す Document クラスを定義します。以下の内容を含める必要があります。
    • プライベートな title 属性 (string)
    • タイトルを受け取り、"Document created: <title>" と出力するコンストラクタ
    • "Document deleted: <title>" と出力するデストラクタ
    • タイトルを返す getTitle() メソッド
  • main.cpp: 入力からドキュメントのタイトルを読み取り、3つのスマートポインタタイプすべてを実証します。
    • 入力されたタイトルを持つ Document への unique_ptr を作成します
    • "Unique owner: <title>" と出力します
    • std::move を使用して、所有権を別の unique_ptr に移譲します
    • "Ownership transferred" と出力します
    • タイトルが "SharedDoc" である新しい Document への shared_ptr を作成します
    • 同じドキュメントを指す2つ目の shared_ptr を作成します
    • use_count() を使用して "Shared owners: <count>" と出力します
    • 共有ポインタの1つから weak_ptr を作成します
    • lock() を使用して弱参照ポインタ経由でドキュメントにアクセスし、"Weak access: <title>" と出力します

スマートポインタを使用するために <memory> をインクルードすることを忘れないでください。スマートポインタの作成には std::make_uniquestd::make_shared を使用してください。デストラクタのメッセージは、プログラムの終了時に各ドキュメントがいつ自動的にクリーンアップされるかを確認するのに役立ちます。

main.cpp で #include "Document.h" を使用してヘッダーファイルをインクルードしてください。

チートシート

スマートポインタは、ヒープメモリを自動的に管理するラッパークラスです。これらを使用するには、<memory> ヘッダーをインクルードしてください。

unique_ptr

独占的な所有権 - 一度に一つのポインタのみがリソースを所有できます:

std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack();  // 通常のポインタのように使用します

// std::move で所有権を移譲
std::unique_ptr<Player> player2 = std::move(player);
// player は nullptr になります

shared_ptr

共有された所有権 - 複数のポインタが同じリソースを所有できます。最後の所有者が破棄されたときにメモリが解放されます:

std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1;  // 両方がリソースを所有

std::cout << p1.use_count();  // 2 を出力

weak_ptr

shared_ptr の所有権を持たないオブザーバーです。循環参照を解決するのに役立ちます:

std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;

if (auto locked = weak.lock()) {  // shared_ptr に変換
    locked->attack();
}

ベストプラクティス: 単一の所有権にはデフォルトで unique_ptr を使用します。複数のオブジェクトがリソースを共有する必要がある場合は shared_ptr を使用します。生存期間を延長せずに監視するには weak_ptr を使用します。生の new よりも make_uniquemake_shared を優先してください。

自分で試してみよう

#include <iostream>
#include <memory>
#include <string>
#include "Document.h"

using namespace std;

int main() {
    string inputTitle;
    cin >> inputTitle;

    // TODO: inputTitle を使用して Document への unique_ptr を作成する
    // std::make_unique を使用する

    // TODO: "Unique owner: <title>" を出力する

    // TODO: std::move を使用して、別の unique_ptr に所有権を移譲する

    // TODO: "Ownership transferred" を出力する

    // TODO: タイトルが "SharedDoc" の新しい Document への shared_ptr を作成する
    // std::make_shared を使用する

    // TODO: 同じドキュメントを指す 2 つ目の shared_ptr を作成する

    // TODO: use_count() を使用して "Shared owners: <count>" を出力する

    // TODO: いずれかの shared_ptr から weak_ptr を作成する

    // TODO: lock() を使用して weak_ptr 経由でドキュメントにアクセスする
    // そして "Weak access: <title>" を出力する

    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン