TechCraft – エンジニアのためのスキルアップメモ

エンジニアのスキルアップを少しでも加速する技術ブログ

スマートポインタの落とし穴:初心者のための5つの注意点

初心者がやりがちなC++スマートポインタの罠5選

C++のスマートポインタ(unique_ptr, shared_ptr, weak_ptr)は、メモリ管理を自動化し、コードの安全性を高める強力なツールです。しかし、初心者が使い始めると、意図しない挙動やエラーに直面することも少なくありません。

本記事では、初心者が陥りがちなスマートポインタの罠を5つ紹介し、それぞれの原因と解決策を具体的なコード例とともに解説します。


1. unique_ptrのコピーによるコンパイルエラー

問題点

unique_ptrは所有権の一意性を保証するため、コピー操作が禁止されています。以下のコードはコンパイルエラーとなります。

#include <memory>

std::unique_ptr<int> ptr1 = std::make_unique<int>(10);
std::unique_ptr<int> ptr2 = ptr1; // エラー:コピーはできない

解決策

所有権を移動するには、std::moveを使用します。

std::unique_ptr<int> ptr2 = std::move(ptr1); // 所有権をptr2に移動

ptr1nullptrとなり、以後使用できません。


2. shared_ptrの循環参照によるメモリリーク

問題点

shared_ptr同士が互いを参照し合うと、参照カウントが0にならず、メモリが解放されません。

#include <memory>

struct Node {
    std::shared_ptr<Node> next;
};

void createCycle() {
    auto node1 = std::make_shared<Node>();
    auto node2 = std::make_shared<Node>();
    node1->next = node2;
    node2->next = node1; // 循環参照
}

解決策

一方をweak_ptrに変更し、循環参照を防ぎます。

struct Node {
    std::weak_ptr<Node> next; // 弱参照に変更
};

3. shared_ptrweak_ptrの誤用によるアクセスエラー

問題点

weak_ptrは所有権を持たないため、直接デリファレンスできません。

std::weak_ptr<int> wp;
std::shared_ptr<int> sp = wp; // エラー:所有権がない

解決策

weak_ptrからshared_ptrを取得するには、lock()を使用します。

std::shared_ptr<int> sp = wp.lock();
if (sp) {
    // 使用可能
}

4. shared_from_thisの未初期化による例外

問題点

shared_from_thisは、shared_ptrによって管理されていないオブジェクトから呼び出すと、std::bad_weak_ptr例外が発生します。

#include <memory>

struct MyClass : std::enable_shared_from_this<MyClass> {
    std::shared_ptr<MyClass> getPtr() {
        return shared_from_this(); // エラー:未初期化
    }
};

void example() {
    MyClass obj;
    auto ptr = obj.getPtr(); // 例外発生
}

解決策

shared_ptrでオブジェクトを管理し、そのインスタンスからshared_from_thisを呼び出します。

auto obj = std::make_shared<MyClass>();
auto ptr = obj->getPtr(); // 正常

5. スマートポインタと生ポインタの混在による二重解放

問題点

スマートポインタと生ポインタで同じリソースを管理すると、二重解放が発生する可能性があります。

int* raw = new int(5);
std::shared_ptr<int> sp(raw);
delete raw; // 二重解放の危険

解決策

スマートポインタにリソースを渡した後は、生ポインタを使用しないようにします。また、make_sharedmake_uniqueを使用することで、安全にリソースを管理できます。

auto sp = std::make_shared<int>(5); // 安全な方法

まとめ

罠の種類 原因 解決策
unique_ptrのコピー 所有権の一意性 std::moveで移動
shared_ptrの循環参照 相互参照 一方をweak_ptrに変更
weak_ptrの誤用 所有権なし lock()shared_ptr取得
shared_from_thisの未初期化 shared_ptrで管理されていない shared_ptrでオブジェクトを管理
スマートポインタと生ポインタの混在 二重解放 生ポインタを使用しない

スマートポインタは便利なツールですが、正しく使用しないと新たな問題を引き起こす可能性があります。基本を理解し、適切に使いこなすことで、安全で効率的なC++プログラミングが可能になります。


参考文献

参考書籍