【初心者向け】C++スマートポインタを使ってみよう

C++スマートポインタ入門(初心者向け)

c++スマートポインタを使いこなす

C++で避けて通れないのがメモリ管理です。
newで確保したメモリをdeleteし忘れたり、逆に二度解放してクラッシュさせてしまったり...。初心者がつまずきやすい箇所でもあります。

そんな問題を解決するために登場したのがスマートポインタです。
C++11以降の標準ライブラリに含まれており、今ではモダンC++の基本ツールになっています。


スマートポインタとは

スマートポインタは「ポインタっぽく使えるけれど、自動でメモリ解放してくれる」オブジェクトです。

スコープを抜けたときに自動でリソースを解放してくれるため、deleteを書き忘れる心配がなくなります。(なんと便利ですね...)

C++標準ライブラリでよく使われるのは次の3種類です。

  • unique_ptr
  • shared_ptr
  • weak_ptr

それぞれの役割と簡単な使い方を見ていきましょう。


unique_ptrについて

unique_ptrは、あるオブジェクトを一人で所有するスマートポインタです。
コピーはできませんが、所有権を別のunique_ptrに移すことは可能です。

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> p = std::make_unique<int>(42);
    std::cout << *p << std::endl;  // 出力: 42

    // コピーは不可
    // std::unique_ptr<int> q = p; // コンパイルエラー

    // 所有権を移す(ムーブ)
    std::unique_ptr<int> q = std::move(p);
    if (!p) {
        std::cout << "pは所有権を失いました" << std::endl;
    }
    std::cout << *q << std::endl; // 出力: 42
}

ここで使っているstd::moveは「所有権を移す」ための仕組みです。
詳しくは 【初心者向け】C++ いい加減ムーブとコピーを理解しよう で解説しています。


shared_ptrについて

shared_ptrは、複数の所有者でリソースを共有できるスマートポインタです。
内部で「参照カウント」を持っており、最後の一人がいなくなった時点で解放されます。

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> a = std::make_shared<int>(100);
    std::shared_ptr<int> b = a;  // 共有
    std::cout << *a << ", " << *b << std::endl; // 出力: 100, 100

    std::cout << "参照カウント: " << a.use_count() << std::endl; // 出力: 2

    a.reset(); // aが解放されてもbが残っているのでまだ有効
    std::cout << *b << std::endl; // 出力: 100
}

ただし、shared_ptr同士でお互いを参照してしまうと循環参照が起き、メモリが解放されなくなることがあります。その場合に使うのが次のweak_ptrです。


weak_ptrについて

weak_ptrは、対象を所有せずに参照するためのポインタです。
shared_ptrと組み合わせて循環参照を防ぐために使います。

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(200);
    std::weak_ptr<int> wp = sp;  // 所有しない参照

    if (auto locked = wp.lock()) {
        std::cout << "値: " << *locked << std::endl; // 出力: 200
    }

    sp.reset(); // 所有者がいなくなったので解放される

    if (wp.expired()) {
        std::cout << "オブジェクトはすでに解放されています" << std::endl;
    }
}

lock()で一時的にshared_ptrを取得し、有効であればアクセスできます。所有者がすでにいなければexpired()trueになります。


まとめ

  • unique_ptr: 一人でリソースを所有する
  • shared_ptr: みんなで共有する
  • weak_ptr: 所有せず様子を見る

まずはこの3つの違いを理解しておけば十分です。
細かい仕組みは使いながら理解していけば問題ないので、ここでは「自動でdeleteしてくれる便利な道具」と覚えておきましょう。

スマートポインタを使うことで、C++のメモリ管理がずっと安全で楽になります。