🌟

C++スマートポインタ入門

2023/06/24に公開

スマートポインタとは

スマートポインタはC++の機能であり、動的なメモリ管理を簡単に行うために使用されます。従来のポインタと比べて、メモリリークや二重解法のリスクを減らし、プログラムの安全性を向上させます。

new/deleteでの目盛り管理の課題点

  • メモリリークの可能性
    • delete漏れ:newで確保したメモリに対して、適切なタイミングでdeleteを行わなかった場合、メモリリークが発生します。例えば、関数内でオブジェクトをnewして返し、呼び出し元で忘れてしまうなど
  • 二重解放の可能性
    • 同じメモリを複数のポインターが所有している場合、それらのポインタが別々のタイミングでdeleteを呼び出すと、同じメモリが二重解放される。二回目の解放ではその番地を他の変数が使用している可能性があり、メモリ破壊を引き起こす

これらの課題はスマートポインターの導入によって解決できます。

C++20スマートポインタの種類

  1. unique_ptr
    • 単一の所有権を持つスマートポインタ。所有権の移譲により、一つのunique_ptrから別のunique_ptrに移すことが可能。
    • 所有権を持つのは常に一つのunique_ptrであり、複数のunique_ptr間で共有することはできない
  2. shared_ptr
    • 共有の所有権を持つスマートポインタ。複数のshared_ptrが同じオブジェクトを所有することが可能。
    • 所有権のカウントが0になると、自動的にメモリの開放が行われる
    • 循環参照を防ぐために、weak_ptrと組み合わせて使用することができる
  3. weak_ptr
    • 非所有権の観察用ポインタ。shared_ptrと組み合わせて使用され、所有権を持たない状態でオブジェクトにアクセスることが可能。
    • weak_ptrは、オブジェクトの寿命に関与せず、循環参照を防ぐために使用される。

スマートポインターの比較

種類 所有権 コピー ムーブ 特徴
unique_ptr 単独 × 所有権の独占、効率的なリソース管理
shared_ptr 共有 参照カウントによる共有、循環参照対策
weak_ptr - × shared_ptrとの親和性、循環参照対策

使いどころとサンプルコード

  1. unique_ptrのサンプル
#include <memory>
#include <iostream>

class Robot {
public:
    void greet() {
        std::cout << "こんにちは!私はロボットです。" << std::endl;
    }
};

int main() {
    // ロボットオブジェクトの所有権をunique_ptrで管理します
    std::unique_ptr<Robot> robotPtr(new Robot());

    // ロボットオブジェクトへの所有権を別のunique_ptrに移譲します
    std::unique_ptr<Robot> anotherRobotPtr = std::move(robotPtr);

    // 移譲されたロボットオブジェクトに挨拶させます
    anotherRobotPtr->greet();

    return 0;
}
  • ロボットオブジェクトの所有権をunique_ptrで管理
  • unique_ptrを使って所有権の移譲を行う
  • 移譲されたロボットオブジェクトに対して挨拶させる
  1. shared_ptrのサンプル
#include <memory>
#include <iostream>

class Robot {
public:
    void dance() {
        std::cout << "踊ります!" << std::endl;
    }
};

int main() {
    // ロボットオブジェクトの所有権をshared_ptrで共有します
    std::shared_ptr<Robot> robotPtr1 = std::make_shared<Robot>();
    std::shared_ptr<Robot> robotPtr2 = robotPtr1; // 所有権の共有

    // 共有されたロボットオブジェクトに対して踊りを指示します
    robotPtr1->dance();
    robotPtr2->dance();

    return 0;
}
  • ロボットオブジェクトの所有権をshared_ptrで共有
  • shared_ptrを使って所有権を共有し、複数のshared_ptrが同じロボットオブジェクトを参照
  • 共有されたロボットオブジェクトに対して踊りを指示
  1. weak_ptrのサンプル
    • weak_ptrはオブジェクトへの観察用ポインタとして使用されるため、循環参照を防ぐ場合に適しています。
#include <memory>

struct Node {
    std::weak_ptr<Node> parent;
};

int main() {
    std::shared_ptr<Node> parentNode = std::make_shared<Node>();
    std::shared_ptr<Node> childNode = std::make_shared<Node>();

    // 循環参照を防ぐため、weak_ptrを使用して親ノードを観察する
    parentNode->child = childNode;
    childNode->parent = parentNode;

    return 0

まとめ

この記事では、スマートポインタの種類と特徴についてまとめ、それぞれのサンプルコードについて説明しました。
なお、C++20以降ではさらに改善されたスマートポインターの機能や追加された新機能もありますので、最新のC++リファレンスやドキュメントを確認してください。
cppリファレンス
スマートポインタを使って効率的で安全なコーディングをお楽しみください!

Discussion