講義メモ
・「6.メモリの管理:6.5 スマートポインタ:リソースの所有権」の続きから
https://rinatz.github.io/cpp-book/ch06-05-smart-pointers/
6.メモリの管理:6.5 スマートポインタ:リソースの所有権【再掲載】
・ポインタはコピー可能なため、ポインタが指す先のリソースを複数のオブジェクトから参照することが可能 ・動的確保したリソースを扱う場合、 誤って delete を忘れたり、同じリソースを複数回 delete したりすることを防ぐために、 どの変数がリソースの所有権(リソースを参照する権利と解放する権利)を持つのかをプログラマが細心の注意を払ってコードを 書く必要がある
提出フォロー:演習:リソースの所有権 project1/p0604501.cpp
・リソースの所有権のサンプルソースを動作可能にしよう ・「a と b のどちらを delete するべきか?」の下で両方をdeleteして、どうなるか確認しよう ⇒ どちらをdeleteしても良いが、両方を消そうとすると、delete済なので異常終了する
作成例
//演習:リソースの所有権 project1/p060501.cpp
#include <iostream>
int main() {
int* a = new int(100); //動的に領域を確保
int* b = a; // b からも a と同じリソースを参照できるようにする。
// a と b のどちらを delete するべきか?
delete a;
std::cout << "delete a is done" << std::endl;
delete b; //対象が存在しないので異常終了する
std::cout << "delete b is done" << std::endl;
return 0;
}
6.メモリの管理:6.5 スマートポインタ:std::shared_ptr
・動的確保したリソースの所有権を共有することができるスマートポインタ ・スマートポインタはヘッダにて提供されている ・内部で所有権を持つオブジェクトの一覧を管理し、所有者がいなくなった時に自動的に delete する仕組みを提供する ・std::shared_ptr オブジェクトを生成するには、 std::make_shared を利用する ・デストラクタはオブジェクトの生存期間が尽きる(消える)とシステムが判断したときに自動的に呼び出す関数 ・デストラクタはクラスの中で記述するものだが(副テキストp.471)、スマートポインタの利用により、 動的に確保された領域に対しても delete が動作するようになっている
演習:std::shared_ptr project1/p060502.cpp
・std::shared_ptrのサンプルソースを試してみよう ・xとyの明示的な消去(delete)ができるかどうか確認しよう
作成例
//演習:std::shared_ptr project1/p060502.cpp
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> x = std::make_shared<int>(100); // int* x = new int(100); の代わり
// 所有者は1人。
{ //ブロックにすることでyの有効範囲(生存期間)を制限している
std::shared_ptr<int> y = x; // 通常のポインタ同様、コピーすることで所有権が共有される
// 所有者が2人に増える。
std::cout << "*y = " << *y << std::endl;
// delete y; //シェアードポインタのdeleteは不可
} // y が破棄されて所有者が1人になる。(yの有効範囲(生存期間)はここまでなので)
std::cout << "*x = " << *x << std::endl;
// delete x; //シェアードポインタのdeleteは不可
return 0;
} // 所有者が0人になるので、 x のデストラクタで自動的に delete が行われる。
6.メモリの管理:6.5 スマートポインタ:std::unique_ptr
・std::shared_ptr と違い、コピーが出来ないのが std::unique_ptr。 ・よって、そのため、確保したリソースの所有者が常に1人になるようにしたい場合に用いる。
演習:std::unique_ptr project1/p060503.cpp
・std::unique_ptrのサンプルソースを試してみよう ・「// std::unique_ptry = x;」のコメントアウトを戻して、どういうエラーになるか確認しよう ⇒ コンパイルエラーになるが、VC++では「C++関数は参照できません -- これは削除された関数です」というエラーが表示され、 誤解を招くので注意。
作成例
//演習:std::unique_ptr project1/p060503.cpp
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> x(new int(100)); //コピーできないスマートポインタで生成される
std::unique_ptr<int> y = x; // コピー出来ないのでコンパイルエラーになる
std::cout << *x << std::endl;
return 0;
} // x が所有しているリソースが解放される。
6.メモリの管理:6.5 スマートポインタ:std::unique_ptr(続き)
・所有権の共有はできないが、std::move を使うことで所有権の移動は出来る ・このことで std::shared_ptr よりも軽快に動作する
演習:std::unique_ptr その2 project1/p060504.cpp
・std::unique_ptrの2つめのサンプルソースを試してみよう ・「所有権を移動したため、x は何も所有していない」ことを確認する処理を追記しよう
作成例
//演習:std::unique_ptr その2 project1/p060504.cpp
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> x(new int(100));
std::unique_ptr<int> y(std::move(x)); // ムーブは出来るため、所有権の移動は可能。
std::cout << "*y = " << *y << std::endl;
// 所有権を移動したため、x は何も所有していない。
std::cout << "*x = " << *x << std::endl; //よってここで異常終了する(コンパイルエラーにはならない)
return 0;
} // y が所有しているリソースが解放される。
※ std::auto_ptr、std::weak_ptrは割愛