C++のデストラクタとは?呼び出しタイミングと参照返しによる挙動の違いを解説
デストラクタ(Destructor)とは、C++のクラスに属する特別なメンバ関数の一つで、クラスのオブジェクトを破棄する役割を担います。
デストラクタが呼び出されるタイミング
デストラクタは、プログラム中でオブジェクトがスコープ外に出ったときに自動的に呼び出されます。具体的には、以下のようなケースが該当します。
- 関数のスコープを抜けるとき
- プログラムが終了するとき
- ローカル変数として初期化されたオブジェクトが属するブロックがスコープ外に出るとき
- delete演算子によってオブジェクトが削除されるとき
サンプルコード1:値を返す場合
まず、次のコードを見て、実行結果を予想してみてください。
#include <iostream>
using namespace std;
int i;
class destructor {
public:
~destructor(){
i=10;
}
};
int valueInitializer() {
i=3;
destructor d1;
return i;
}
int main() {
cout<<"i = "<<valueInitializer()<<endl;
return 0;
}
実行結果
i = 3
コードの解説
このコードでは、まずグローバル変数 i を宣言し、valueInitializer() 関数の中でその値を書き換えています。具体的には、変数に3を代入した後、オブジェクト d1 を生成し、最後に値を返しています。
さて、出力はいくつになるでしょうか? 答えは「3」です。正しく予想できた方は素晴らしい! もし「10」だと思った方も心配いりません。ここで何が起きているのかを確認していきましょう。
先ほど説明したとおり、デストラクタは関数がスコープを抜けるタイミングで呼び出されます。つまり、関数がスコープを抜ける前に、すでに戻り値として3が返されているため、デストラクタ内の i = 10 の代入が行われる前に出力内容が確定するのです。
サンプルコード2:参照を返す場合
次にもう一つの例です。よく似たコードですが、今度の出力はどうなるでしょうか?
#include <iostream>
using namespace std;
int i;
class destructor {
public:
~destructor(){
i=10;
}
};
int& valueInitializer() {
i=3;
destructor d1;
return i;
}
int main() {
cout<<"i = "<<valueInitializer()<<endl;
return 0;
}
実行結果
一見ほぼ同じコードに見えますが、こちらは「i = 10」と表示されます。
なぜ結果が変わるのか?
ポイントは、今回は変数の参照(リファレンス)を返している点です。デストラクタが呼び出されて i の値が10に書き換わっても、関数は値そのものではなく参照を渡しているため、書き換え後の最新の値である「10」が出力されます。
このように、値を返すか参照を返すかによって、デストラクタの実行タイミングと結果の関係が大きく変わります。オブジェクトの寿命とスコープの仕組みをしっかり理解しておくことは、C++プログラミングにおいて非常に重要な基礎知識となるでしょう。
-
C++で学ぶ式ツリー(Expression Tree)の基本と具体例
式ツリーとは何か式ツリー(Expression Tree)とは、二分木の一種であり、木の各ノードが「演算子」または「オペランド(被演算子)」のいずれかで構成される特殊なデータ構造です。数式を木構造として表現することで、コンパイラや電卓アプリなどが数式を効率的に解析・評価できるようになります。ノードの役割式ツリーにおける各ノードは、次のように役割が分かれています。葉ノード(リーフノード):オペランド(数値や変数)を表します。非葉ノード(内部ノード):演算子(+、-、*、/ など)を表します。つまり、計算の対象となる値は必ず葉に配置され、それらをどのように処理するかを示す演算子が親ノードとして上に
-
C++で解く「3nスライスのピザ」問題 ― 動的計画法でスライスの合計を最大化する方法
問題の概要 大きさがまちまちの 3n 個のスライスからなるピザがあるとします。私と友人2人は、次のルールに従ってピザを取っていきます。 私が任意のスライスを1枚選びます。 友人のAmalは、私が選んだスライスの反時計回り方向に隣接するスライスを取ります。 友人のBimalは、私が選んだスライスの時計回り方向に隣接するスライスを取ります。 ピザのスライスがなくなるまで、この手順を繰り返します。 各スライスの大きさは、時計回りの順に並べた環状配列 slices として与えられます。求めるのは、私が手にできるスライスの大きさの合計の最大値です。 入出力例 入力が [9, 8, 6, 1, 1,