カテゴリ: C++ 更新日: 2026/02/04

C++スマートポインタ完全攻略!unique_ptr / shared_ptr / weak_ptrの違いと使い方

スマートポインタ (unique_ptr, shared_ptr, weak_ptr)
スマートポインタ (unique_ptr, shared_ptr, weak_ptr)

先生と生徒の会話形式で理解しよう

生徒

「先生、C++の『ポインタ』ってメモリの管理が難しくて、すぐにプログラムが壊れそうで怖いです……。」

先生

「その気持ち、よく分かります。昔のC++では自分で『確保』と『解放』を完璧に管理しなければなりませんでしたが、今は『スマートポインタ』という賢い仕組みがあるんですよ。」

生徒

「スマートポインタを使うと、自動でお片付けしてくれるんですか?」

先生

「その通り!メモリ漏れを防いでくれる頼もしい味方です。今日はその種類と使い方をマスターしましょう!」

1. スマートポインタとは?

1. スマートポインタとは?
1. スマートポインタとは?

C++のプログラミングにおいて、最も注意しなければならないのがメモリ管理です。 パソコンのメモリは無限ではありません。プログラムで「データを入れるための場所を貸して!」とお願い(確保)したら、使い終わった後に「もう使い終わったから返します!」と宣言(解放)する必要があります。

しかし、人間はうっかり忘れてしまう生き物です。返し忘れると、パソコンのメモリがどんどん使われっぱなしになり、最終的にはパソコンが重くなったり動かなくなったりします。これをメモリリークと呼びます。

そこで登場するのがスマートポインタです。これは、普通のポインタを「賢い箱」で包んだものです。 この箱は、自分自身が不要になった瞬間に、中に入っているメモリを自動的に返却してくれます。まるで、ゴミを自動で捨ててくれるスマートゴミ箱のような存在なのです。

2. unique_ptr(ユニークポインタ)の使い方

2. unique_ptr(ユニークポインタ)の使い方
2. unique_ptr(ユニークポインタ)の使い方

まず最初に覚えるべきなのが std::unique_ptr です。「unique(ユニーク)」とは「唯一の」という意味があります。 その名前の通り、「あるデータを指し示すことができるのは、世界で自分一人だけ」という強いルールを持っています。

コピー(二人で共有すること)は禁止されていますが、その分仕組みがシンプルで動作も高速です。 基本的には、この unique_ptr を使うのがC++の王道とされています。


#include <iostream>
#include <memory> // スマートポインタを使うために必要

int main() {
    // 整数を入れるメモリを確保し、unique_ptrで管理する
    // std::make_uniqueを使うのが一番安全で推奨される作り方です
    std::unique_ptr<int> myData = std::make_unique<int>(100);

    // 普通のポインタと同じように * を使って中身を見れる
    std::cout << "中身の値: " << *myData << std::endl;

    // myDataがこの { }(スコープ)を抜けるとき、
    // 自動的にメモリが解放されます。deleteを書く必要はありません!
    return 0;
}

中身の値: 100

3. shared_ptr(シェアードポインタ)で共有する

3. shared_ptr(シェアードポインタ)で共有する
3. shared_ptr(シェアードポインタ)で共有する

次に紹介するのは std::shared_ptr です。「shared(シェアード)」は「共有された」という意味ですね。 unique_ptr とは違い、一つのデータを複数のポインタで共有して持つことができます。

「今、何人がこのデータを使っているか?」というカウンターを持っていて、そのカウンターがゼロになった時(誰も使わなくなった時)に初めてメモリを解放します。 家族全員で一台のテレビを共有し、最後の人が部屋を出て電気を消すようなイメージです。


#include <iostream>
#include <memory>

int main() {
    // shared_ptrを作成
    std::shared_ptr<int> p1 = std::make_shared<int>(500);

    {
        // p2にコピーする。これで二人で同じデータを指している状態
        std::shared_ptr<int> p2 = p1;
        std::cout << "p2の中身: " << *p2 << std::endl;
        std::cout << "使っている人数: " << p1.use_count() << std::endl;
    } // ここでp2が消える

    std::cout << "p2が消えた後の人数: " << p1.use_count() << std::endl;

    return 0;
}

p2の中身: 500
使っている人数: 2
p2が消えた後の人数: 1

4. weak_ptr(ウィークポインタ)の役割

4. weak_ptr(ウィークポインタ)の役割
4. weak_ptr(ウィークポインタ)の役割

最後に std::weak_ptr です。「weak(ウィーク)」は「弱い」という意味です。 これは shared_ptr をサポートするための特殊なポインタです。

shared_ptr 同士がお互いにお互いを指し合ってしまうと、いつまで経ってもカウンターがゼロにならず、メモリが解放されないという問題(循環参照)が発生します。 weak_ptr「データを見守ることはできるけれど、所有権(消さないで!と言う権利)は持たない」という控えめなポインタです。 これにより、お互いを見合って動けなくなる状況を防ぐことができます。

5. なぜスマートポインタを使うべきなのか?

5. なぜスマートポインタを使うべきなのか?
5. なぜスマートポインタを使うべきなのか?

未経験の方からすると、「なんだか難しそう」と感じるかもしれません。しかし、スマートポインタを使わない昔ながらのプログラミング(生ポインタと delete)は、まるで綱渡りのような危険が伴います。

もし、プログラムの途中でエラーが発生して止まってしまったら? delete を書いた行までたどり着けなかったら? スマートポインタなら、どんな終わり方をしても、その変数が消える瞬間に必ず後片付けを保証してくれます。 「安全第一」なソフトウェアを作るためには、現代のC++においてスマートポインタを避けて通ることはできません。

6. スマートポインタを使いこなすコツ

6. スマートポインタを使いこなすコツ
6. スマートポインタを使いこなすコツ

最後に、どのポインタをいつ使うべきかの判断基準をお伝えします。 パソコンの操作すら慣れていない方でも、この優先順位だけ覚えておけば大丈夫です。

  1. まずは unique_ptr を検討する: ほとんどの場合はこれで十分です。持ち主を一人に決めることで、プログラムがシンプルになります。
  2. どうしても共有が必要なら shared_ptr: 複数の場所から一つのデータにアクセスしたい場合のみ使います。
  3. 補助として weak_ptr: 複雑な構造を作るとき、補助的に使います。

このように、それぞれの役割を分担させることで、バグが少なく、読みやすい綺麗なプログラムを書くことができるようになります。

7. スマートポインタを使った実例プログラム

7. スマートポインタを使った実例プログラム
7. スマートポインタを使った実例プログラム

最後に、少し実践的なコードを見てみましょう。 例えば、ゲームのキャラクターの情報をスマートポインタで管理する場合です。


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

// キャラクターを表す小さな設計図
struct Character {
    std::string name;
    Character(std::string n) : name(n) {
        std::cout << name << " が誕生しました!" << std::endl;
    }
    ~Character() {
        std::cout << name << " がメモリから消去されました。" << std::endl;
    }
};

int main() {
    // 勇者をunique_ptrで作る
    std::unique_ptr<Character> hero = std::make_unique<Character>("勇者");

    std::cout << "冒険の途中..." << std::endl;

    // ここでmain関数が終わると、heroが消えるので、
    // 自動的に「消去されました」と表示されます。
    return 0;
}

勇者 が誕生しました!
冒険の途中...
勇者 がメモリから消去されました。

このように、プログラムの終了と共に自動で後片付けが実行されるのがスマートポインタの最大の魅力です。 手動で delete を呼ばなくてもいいので、安心してコードを書くことができますね。

カテゴリの一覧へ
新着記事
New1
C++
C++のメンバアクセス演算子を完全解説!初心者でもわかる . → :: の使い方まとめ
New2
Rust
Rustの文字列を極める!&str(文字列スライス)の基本概念とString型との違い
New3
C++
C++のキャスト演算子を完全解説!dynamic_cast・static_cast・const_cast・reinterpret_castを初心者向けに説明
New4
C++
C++開発のIDE選びを完全ガイド!初心者でもわかるCLion・Eclipse CDT・Qt Creator比較
人気記事
No.1
Java&Spring記事人気No1
C++
C++の主要な実装をわかりやすく解説!GCC・Clang・MSVCの違いと特徴
No.2
Java&Spring記事人気No2
C言語
C言語を学ぶ初心者におすすめの環境構築手順【2025年版】
No.3
Java&Spring記事人気No3
C言語
C言語をオンラインで実行できる便利なコンパイラサービスまとめ【初心者向け】
No.4
Java&Spring記事人気No4
C言語
C言語のソースコードとヘッダファイルの役割とは?初心者向けにわかりやすく解説!
No.5
Java&Spring記事人気No5
C言語
Visual Studio CodeでC言語を実行する方法【拡張機能の設定と実行手順】
No.6
Java&Spring記事人気No6
C言語
C言語開発でよく使われるエディタとIDEランキング【初心者向け完全ガイド】
No.7
Java&Spring記事人気No7
C++
C++リンカとコンパイラのオプション設定を完全ガイド!初心者にもわかる開発環境の基礎
No.8
Java&Spring記事人気No8
C言語
C言語の列挙型(enum)の使い方を完全ガイド!初心者でもわかる基本操作