第5回はスマートポインタになります。 C++ではメモリ確保を行う場合、自動で解放しないので解放処理を書く必要があります。 1: #include <iostream> 2: 3: using namespace std; 4: 5: class Hoge 6: { 7: public: 8: Hoge() 9: { 10: cout << "Constructor" << endl; 11: } 12: ~Hoge() 13: { 14: cout << "Destructor" << endl; 15: } 16: 17: int num; 18: }; 19: 20: int main() 21: { 22: //メモリ確保 23: Hoge* p1 = new Hoge(); 24: Hoge* p2 = new Hoge[5]; 25: 26: //初期化 27: p1->num = 10; 28: for (int i = 0; i < 5; i++) 29: { 30: (p2+i)->num = i; 31: } 32: 33: //表示 34: cout << p1->num << endl; 35: for (int i = 0; i < 5; i++) 36: { 37: cout << (p2+i)->num << endl; 38: } 39: 40: //メモリ解放 41: delete p1; 42: delete [] p2; 43 44: return 0; 45: } 40行目から先のdeleteを書かないと、確保したメモリが終了しても解放されずに残ってしまいます。 1: int main() 2: { 3: //メモリ確保 4: unique_ptr<Hoge> p1(new Hoge); 5: unique_ptr<Hoge[]> p2(new Hoge[5]); 6: 7: //初期化 8: p1->num = 10; 9: for (int i = 0; i < 5; i++) 10: { 11: p2[i].num = i; 12: } 13: 14: //表示 15: cout << p1->num << endl; 16: for (int i = 0; i < 5; i++) 17: { 18: cout << p2[i].num << endl; 19: } 20: 22: return 0; 23: } deleteを書いていませんが、実行するとデストラクタが呼ばれることが分かります。 次にshaerd_ptrの例を見ます。 1: int main() 2: { 3: //メモリ確保 4: shared_ptr<Hoge> p1 = make_shared<Hoge>(); 5: 6: cout << p1.use_count() << endl;//1 7: 8: { 9: //p2に代入 10: shared_ptr<Hoge> p2 = p1; 11: 12: cout << p1.use_count() << endl;//2 13: 14: p2->num = 10; 15: }//p2はここで解放される(Hogeは破棄されない) 16: 17: cout << p1.use_count() << endl;//1 18: 19: cout << p1->num << endl;//p2で代入した10が表示される 20: 21: return 0; 22: } shaerd_ptrは参照カウント方式で、オブジェクトを参照するshaer_ptrが0になったときにdeleteします。 次にweak_ptrを使う例について説明します。 1: #include <iostream> 2: #include <memory> 3: 4: using namespace std; 5: 6: class Hoge 7: { 8: public: 9: Hoge() 10: { 11: cout << "Constructor" << endl; 12: } 13: ~Hoge() 14: { 15: cout << "Destructor" << endl; 16: } 17: 18: shared_ptr<Hoge> ptr; 19: }; 20: 21: int main() 22: { 23: //メモリ確保 24: shared_ptr<Hoge> p1(new Hoge); 25: shared_ptr<Hoge> p2(new Hoge); 26: 27: p1->ptr = p2; 28: p2->ptr = p1; 29: 30 return 0; 31: } このプログラムだと循環参照が発生しているため、メモリの解放が行われません。 1: class Hoge 2: { 3: public: 4: Hoge() 5: { 6: cout << "Constructor" << endl; 7: } 8: ~Hoge() 9: { 10: cout << "Destructor" << endl; 11: } 12: 13: weak_ptr<Hoge> ptr;//weak_ptrに変える 14: }; これによってスコープを抜けた時点でカウンタが残っていてもdeleteが呼ばれるため先ほどの循環参照の問題がなくなりました。 1: int main() 2: { 3: //メモリ確保 4: shared_ptr<Hoge> shar_p = make_shared<Hoge>(); 5: weak_ptr<Hoge> weak_p; 6: 7: weak_p = shar_p; 8: 9: //weak_ptrからは直接操作出来ないので、lock()を使うことにより取得出来る 10: if (auto p = weak_p.lock()) 11: { 12: p->num = 10; 13: } 14: 15: cout << shar_p->num << endl;//10が表示される 16: 17: shar_p.reset();//解放 18: 19: //解放されているかの確認はexpired()で出来る 20: if (weak_p.expired()) 21: { 22: cout << "expired" << endl; 23: } 24: 25: return 0; 26: } スマートポインタを利用することによって、メモリ解放に関する問題を解決することが出来ます。 以上でスマートポインタの説明を終了します。 |