初心者がやりがちな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に移動
ptr1
はnullptr
となり、以後使用できません。
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_ptr
とweak_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_shared
やmake_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++プログラミングが可能になります。
参考文献
- C++のスマートポインタとは何?まとめてみた
- shared_ptr - basics and internals with examples
- C++ weak_ptr | How weak_ptr works in C++ with examples?