404 Not Found

404 Not Found


nginx

スマートポインタ

[第]45[課では]moveセマンティクスについて学びました。

[現在]、[スマートポインタについて詳しく見ていきましょう――[現代の]C++における[メモリ管理の中核となるツール]です。

[スマートポインタを使えば]、[メモリリークを心配する必要は][もうありません]。


1. スマートポインタ[概要]

(1) 1.1 スマートポインタとは?

スマートポインタ[とは][動的メモリを]管理する[テンプレートクラス]であり、メモリを[自動的に解放]する(RAII)。

[3種類の]スマートポインタ:

スマートポインタ [機能] [適用シーン]
unique_ptr [独占所有権] [唯一の所有]object
shared_ptr [共有所有権] [複数の場所から同一のオブジェクトにアクセスする必要がある]
weak_ptr [弱]参照 [解決]ループ参照


2. unique_ptr

基本的な使い方

unique_ptr [は][排他的所有権][を持つ]スマートポインタであり、[コピーはできず]、[移動のみ可能]です。

例:unique_ptr[基本用法] (難易度 ⭐)

▶ サンプル 2: codeexample (難易度 ⭐)

CPP
#include iostream
#include memory

int main() {
 std::unique_ptrint p1(new int(42));
 std::cout << *p1 << std::endl; // output:42
 
 // std::unique_ptrint p2 = p1; // ❌!
 std::unique_ptrint p2 = std::move(p1); // ✅
 std::cout << *p2 << std::endl; // output:42
 
 return 0;
} // p2
▶ 試してみよう

(2) 2.2 [カスタムデリーター]

例:[用]unique_ptr[管理]file (難易度 ⭐⭐)

CPP
#include iostream
#include memory
#include cstdio

//:
struct FileDeleter {
 void operator()(FILE* fp) const {
 if (fp) {
 fclose(fp);
 std::cout << "..." << std::endl;
 }
 }
};

int main() {
 std::unique_ptr<FILE, FileDeleter> file(fopen("test.txt", "w"));
 // fclose,unique_ptrFileDeleter
 
 return 0;
}


3. shared_ptr

基本的な使い方

shared_ptr [は][所有権を共有する][スマートポインタ]であり、参照カウントを用いてメモリを[管理]します。

例:shared_ptr[基本用法] (難易度 ⭐)

CPP
#include iostream
#include memory

int main() {
 std::shared_ptrint p1 = std::make_sharedint(42);
 std::cout << ":" << p1.use_count() << std::endl; // 1
 
 {
 std::shared_ptrint p2 = p1; //,+1
 std::cout << ":" << p1.use_count() << std::endl; // 2
 } // p2,reference-1
 
 std::cout << ":" << p1.use_count() << std::endl; // 1
 
 return 0;
}

(2) 3.2 make_shared 対 new

[推奨用法]: std::make_shared [ではなく] new

[比較] new make_shared
例外[安全] [漏洩の可能性あり] [安全]
パフォーマンス [二次分配] [一次分配]
コード[簡潔] [冗長] [簡潔]
CPP
// ...
auto p1 = std::make_sharedint(42);

// ...
std::shared_ptrint p2(new int(42));


4. weak_ptr

(1) 4.1 なぜ weak_ptr が必要なのか?

[問題]: shared_ptr [原因となり得る]ループ参照、メモリリーク。

例:loopreference(難易度 ⭐⭐⭐)

CPP
#include iostream
#include memory

struct Node {
 std::shared_ptrNode next; //!
 ~Node() { std::cout << "Node destroyed" << std::endl; }
};

int main() {
 auto n1 = std::make_sharedNode();
 auto n2 = std::make_sharedNode();
 
 n1->next = n2; // n1referencen2
 n2->next = n1; // n2referencen1(reference)
 
 return 0;
} // ❌ n1andn2(memory leaks)

(2) 4.2 [使用]weak_ptr[解消]ループ参照

[解決策]: [そのうちの1つ] shared_ptr [を] weak_ptr [に変更する]。

CPP
struct Node {
 std::weak_ptrNode next; // weak_ptr,
 ~Node() { std::cout << "Node destroyed" << std::endl; }
};

int main() {
 auto n1 = std::make_sharedNode();
 auto n2 = std::make_sharedNode();
 
 n1->next = n2; // ...
 n2->next = n1;
 
 return 0;
} // ✅


5. スマートポインタ[選択ガイド]

(1) 5.1 [選び方]?

[シーン] [おすすめ]
[唯一所有] unique_ptr
[共有所有] shared_ptr
[観察者] weak_ptr [または元]ポインタ
配列 unique_ptr<T>

(2) 5.2 [してはいけないこと]

エラー [説明]
[複数の原始]ポインタ[でshared_ptrを初期化してはいけません] [重複した解放を引き起こすため]
[ポインタとスマートポインタを混在させてはならない] [RAIIを破壊する]
[手動で呼び出さないでください]delete [スマートポインタに]管理を任せる


6. 演習:スマートポインタ[リソース管理]

▶ サンプル 1: [スマートポインタを使用して]データベース接続を管理する (難易度 ⭐⭐⭐)

CPP
#include iostream
#include memory

// ...
class DatabaseConnection {
public:
 DatabaseConnection() {
 std::cout << "..." << std::endl;
 }
 
 ~DatabaseConnection() {
 std::cout << "..." << std::endl;
 }
 
 void query(const std::string& sql) {
 std::cout << "SQL:" << sql << std::endl;
 }
};

int main() {
 // unique_ptr
 std::unique_ptrDatabaseConnection conn(new DatabaseConnection());
 conn->query("SELECT * FROM users");
 
 return 0;
} // ...
▶ 試してみよう

❓ よくある質問

Q unique_ptrとshared_ptr、どちらが速い?
A unique_ptrの方が速い(参照カウントのオーバーヘッドがないため)、unique_ptrを優先して使用すること。

Q [いつ]ポインタを使うのか?
A - [所有権を持っていない場合]([オブザーバー]) - [Cライブラリと]やり取りする場合 - [パフォーマンスに極めて敏感な場合]([ただし、通常は必要ない])

Q:shared_ptrはスレッドセーフですか? A:- 参照カウントの変更はスレッドセーフです - ただし、参照先のオブジェクト自体はスレッドセーフではありません(ミューテックスによる保護が必要です)


📖 まとめ

[知識ポイント] [要点]
unique_ptr [排他所有権]、[コピー不可]
shared_ptr [共有所有権]、参照[カウント]
weak_ptr [弱]参照,[ループ参照の]解除
make_shared [推奨用法]、例外[安全]
[選択の原則] [優先]unique_ptr、[必要な場合にのみ]shared_ptr

📝 練習問題

  1. **初心者向け(難易度 ⭐):[use] unique_ptr [動的に割り当てられた] int を [管理] し、[use] make_unique [で作成] します。[try] unique_ptr を [コピー] すると([should] コンパイル [fail] するはず)、[use] move に変更してください。

  2. **中級(難易度 ⭐⭐):[用] shared_ptr [複数の] object [が同じリソースを共有する] ようにする。[2つの] shared_ptr [を同じ] object [に] 作成し、use_count() を出力して [参照] カウントの変化を[観察]する。

  3. **上級(難易度 ⭐⭐⭐):[使用] weak_ptr [解決] shared_ptr のループ参照[問題]。[作成] クラス A [と] クラス B [が互いに] shared_ptr を保持し、[確認] メモリリークが発生する。[代わりに] weak_ptr を使用し、[正しく解放されることを確認]する。



[次のレッスン]:テンプレートメタプログラミング[入門](#47)

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%