関数内に宣言した変数とポインタとnewとmallocとコンストラクタとデストラクタについて
Javaの参照型はnewした時にその実体が生成されるわけだけど、C++はどうなってるのかテストしてみた。
テストは以下の4パターンで、main関数内に明示的なブロックを作ってその中に宣言しているので、スタックに確保されるものはブロックの終了で寿命が終わるハズ。
ブロック内で Hoge クラスのメンバ関数 func を呼んでいるがこける場合もある。
こけるものは func を呼ばないパターンを追加している。
条件
- パターン
- 値の場合
- ポインタの場合
- ポインタをnewした場合
- ポインタをmallocした場合
- コード
class Hoge{ public: Hoge(void){ printf("Hoge Constructor\n"); }; //コンストラクタ ~Hoge(void){ printf("Hoge Destructor\n"); }; //デストラクタ void func(void){ printf("Hoge func\n"); }; //テスト関数 }; int main(void){ printf("Start Block\n"); //明示的なブロック { //この中身を変えていくよー } printf("End Block\n"); return 0; };
結果
条件 | ブロックの中身 | 実行結果 |
---|---|---|
値の場合 | Hoge hoge; printf("Create Hoge\n"); hoge.func(); |
Start Block Hoge Constructor Create Hoge Hoge func Hoge Destructor End Block |
ポインタの場合 1 | Hog*e hoge; printf("Create Hoge\n"); hoge->func(); |
Start Block Create Hoge //エラー |
ポインタの場合 2 | Hog*e hoge; printf("Create Hoge\n"); |
Start Block Create Hoge End Block |
ポインタをnewした場合 | Hoge* hoge = new Hoge(); printf("Create Hoge\n"); hoge->func(); |
Start Block Hoge Constructor Create Hoge Hoge func End Block |
ポインタをmallocした場合 | Hoge* hoge = (Hoge*)malloc(sizeof(Hoge)); printf("Create Hoge\n"); hoge->func(); |
Start Block Create Hoge Hoge func End Block |
条件 | 宣言時にコンストラクタを | ブロック終了時にデストラクタを |
---|---|---|
値の場合 | 通る | 通る |
ポインタの場合 | 通らない | 通らない |
ポインタをnewした場合 | 通る | 通らない |
ポインタをmallocした場合 | 通らない | 通らない |
- 値の場合
宣言時にコンストラクタを通り、ブロックを抜ける時にデストラクタが動く。
スタックに確保されていることがわかる。
宣言しただけではnullなJavaの感覚で使うとまずいので注意。
- ポインタの場合
コンストラクタが呼ばれておらず、func呼び出しでエラー。
アドレスが(スタックに?)確保されているだけなので実体は存在していない。
(ブロックの終了とともにアドレスは解放されてる?)
- ポインタをnewした場合
new時にコンストラクタが呼び出されるがブロックを抜けてもデストラクタを通らない。
ヒープに確保されていることがわかる。
ちゃんとdeleteしないとリークする。
(アドレスはスタックに、実体はヒープにあるのでブロック終了前に開放しないとメモリリークする?)
- ポインタをmallocした場合
コンストラクタもデストラクタも通らない。でも実体はあるんで作った後で初期化、使い終わったらfreeしないとだめ。
(アドレスはスタックに、実体はヒープにあるのでブロック終了前に開放しないとメモリリークする?)
結局デストラクタを勝手に呼んでくれる値の宣言がすごくいいんだけどなんか怖い。
C++ならnewでいいけどmallocはより低レベルで作業できそう。