書籍転載
文法からはじめるプログラミング言語Microsoft Visual C++入門
C++のクラスをマスターしよう(前編)
―第10章 クラス〜オブジェクト指向プログラミング(前編)―
WINGSプロジェクト 矢吹 太朗(監修 山田 祥寛)
2010/05/19 |
|
|
●10.1.7 デストラクタ
デストラクタはオブジェクトを削除する際に呼ばれるメソッドですが、コンパイラが作るデストラクタは何の処理も行いません。オブジェクトを削除する際に特別な処理を行いたい場合には、自分でデストラクタを実装しなければなりません。
デストラクタは次のように定義します(宣言と定義を分けることもできます)。デストラクタには引数や戻り値はありません。
削除の際にフィールドnameの値を表示するようなデストラクタを持つクラスPersonを使って、オブジェクトが削除されるようすを観察しましょう。
#include <iostream>
#include <string>
#include <memory>
using namespace std;
using namespace std::tr1;
class Person
{
string name;
public:
Person(string name) : name(name) {}
//nameの値を表示するようなデストラクタ
~Person() { cout<<name<<"は削除された\n"; }
};
int main()
{
Person a1("Taro"); //自動メモリに生成
Person* pA2=new Person("Jiro"); //フリーストアに生成
Person* pA3=new Person("Saburo"); //フリーストアに生成
shared_ptr<Person> pA4(new Person("Shiro")); //フリーストアに生成
delete pA2; //オブジェクトの削除
} |
|
[サンプル]10-destructor1.cpp |
実行結果は以下のようになります。
Jiroは削除された
Shiroは削除された
Taroは削除された |
このコードでは以下の4つのオブジェクトを生成しています。
(1)Person a1("Taro");として自動メモリに生成したオブジェクトは、そのスコープが終了すると削除されます。
(2)new Person("Jiro")としてフリーストアに生成したオブジェクトは、それを指すポインタpA2をdeleteすることで削除されます。
(3)new Person("Saburo")としてフリーストアに生成したオブジェクトは、delete文がないため削除されません。この例では、すぐにプログラムが終了し、その際にプログラムが利用していたメモリはすべて解放されますが、プログラムが動き続ける場合には、このようなdelete文の書き忘れはメモリリークの原因になります。
(4)new Person("Shiro")としてフリーストアに生成したオブジェクトは、スマートポインタpA4で管理しているので、delete文を書かなくても削除されます(3.4.4項)。それぞれが生成されてから削除されるまでのようすを図示すると図10-3のようになります。
|
図10-3 4つのオブジェクトが生成されてから削除されるまでのようす |
デストラクタは再帰的に呼ばれます。つまり、クラスPersonのメンバとして別のクラスAがあるときに、Personオブジェクトを削除すれば、そのメンバであるAオブジェクトも削除されます。このことは、以下のコードで確認できます。
#include <iostream>
#include <string>
using namespace std;
struct A
{
~A() { cout<<"Aオブジェクトは削除された\n"; }
};
class Person
{
string name;
A a; //Aオブジェクトをメンバに持つ
public:
Person(string name) : name(name) {}
~Person() { cout<<name<<"は削除された\n"; }
};
int main()
{
Person a1("Taro");
Person* pA2=new Person("Jiro");
delete pA2;
} |
|
[サンプル]10-destructor2.cpp |
プログラムの実行結果は次のようになります。
Jiroは削除された
Aオブジェクトは削除された
Taroは削除された
Aオブジェクトは削除された |
Aオブジェクトが2回削除されているので、a1のメンバと*pA2のメンバの両方が削除されていることがわかります。「A a;」のように生成されたオブジェクトは、それを保持するAオブジェクトが削除されれば削除されることがわかります。
●10.1.8 デストラクタの役割
これまで紹介したデストラクタは、すべてレポートを表示させるためだけのもので、特に重要な役割を果たしているわけではありません。デストラクタが重要になるのは、メンバがフリーストアに配置される場合です。
次の例においては、Personオブジェクトが削除されるときに、ポインタpAが指すAオブジェクトをdelete pA;として削除しなければなりません。これを忘れると、Aオブジェクトがフリーストア内に残り、メモリリークの原因になります。delete pA;はPersonのデストラクタ内で実行します。このように、利用したオブジェクトを最後に削除するのがデストラクタの本来の役割です*5。
*5 *pA を別の機会に削除することもできますが、慣れないうちは、それを生成したクラス(ここではPerson)のデストラクタで削除するようにしておいてください。 |
#include <iostream>
#include <string>
using namespace std;
struct A
{
~A() { cout<<"Aオブジェクトは削除された\n"; }
};
class Person
{
string name;
A* pA;
public:
//Aオブジェクトをフリーストアに生成するコンストラクタ
Person(string name) : name(name), pA(new A) {}
//Aオブジェクトを削除するデストラクタ
~Person() {
delete pA;
cout<<name<<"は削除された\n";
}
};
int main()
{
Person a1("Taro");
Person* pA2=new Person("Jiro");
delete pA2;
} |
|
[サンプル]10-destructor3.cpp |
実行結果は次のようになり、Aオブジェクトが削除されていることがわかります。
Aオブジェクトは削除された
Jiroは削除された
Aオブジェクトは削除された
Taroは削除された |
~Person()の中にdelete pA;を書かなければ、Bオブジェクトは削除されないままフリーストアに残り、メモリリークの原因になります。
オブジェクトの削除を常に意識するのが面倒な場合には、スマートポインタ(3.4.5項を参照)を利用します。~Person()の中にdelete文を書かなくても、Aオブジェクトは削除されます。
#include <iostream>
#include <string>
#include <memory>
using namespace std;
using namespace tr1;
struct A
{
~A() { cout<<"Aオブジェクトは削除された\n"; }
};
class Person
{
string name;
shared_ptr<A> pA; //スマートポインタを利用
public:
Person(string name) : name(name), pA(new A) {}
~Person() { cout<<name<<" は削除された\n"; }
};
int main()
{
Person a1("Taro");
shared_ptr<Person> pA2(new Person("Jiro")); //スマートポインタを利用
} |
|
[サンプル]10-destructor4.cpp |
このコードにはdelete文はありませんが、実行結果は次のようになり、すべてのオブジェクトを削除できていることがわかります。
Jiro は削除された
Aオブジェクトは削除された
Taro は削除された
Aオブジェクトは削除された |
Insider.NET 記事ランキング
本日
月間