1

以下のコードを検討してください。

#include <iostream>
#include <stdexcept>

using namespace std;

int i;

class A{
    public:
    ~A(){i=10;}
    };

int func1()
{
    i=3;
    A Ob; // -> here local object , hence created and destroyed
    return i;
    }

int& func2()
{
    i=8;
    A obj;
    return i;
    }

int func3()
{
    i=8;
    {A  obj;}
    return i;
    }





int main()
{

cout << "i : " <<func1() << endl;
cout << "i : " <<func2() << endl;
cout << "i : " <<func3() << endl;
return(0);
}

出力:

$ ./TestCPP
i : 3
i : 10
i : 10

最初に i が 3 である理由を誰かが説明できますか? ではfunc1()A Obはローカル変数であるため、作成および破棄されます。それが破壊されると、 i を変更するデストラクタが呼び出され、 になると10予想iされますが10、答えはi : 3.

4

5 に答える 5

4

を呼び出したとき、スタック オブジェクトはまだスコープ内にあるため、 のデストラクタがまだ呼び出されていないためreturn、 の値は 3 のままです。戻り値が設定された、関数のスタックが巻き戻されると、スタック オブジェクトが削除されます。iA

これが当てはまらない場合、スタック オブジェクトが実行中に破棄される可能性がある場合を想像してみてくださいreturn。関数からローカル値を返すにはどうすればよいでしょうか?

コメントへの対応

@paddyその場合、func2とfunc3を説明できますか?

表面上はfunc2は とほとんど同じに見えfunc1、8 を返すはずだと考えても仕方ありません。しかし、ここでの違いは、int&ではなくint. つまり、 への参照iによって返されreturn i;ます。iスタックが巻き戻しを開始するときは 8ですが、objが破棄され、戻り値が呼び出し元にポップバックされるまでの の値iは 10 です。参照を返したので、戻り値は逆参照され、i(10の現在の値) 使用されている。

それfunc3はさらに簡単だからです。intこれは、 と同様に法線を返しますfunc1。ただし、インスタンスA obj;は独自のブロック スコープ内にあります: { A obj; }. したがって、 の前に破棄され、関数から戻ったときreturnの の値は 10 です。i

于 2013-06-28T01:58:22.883 に答える
2

標準から (C++11、3.7.3):

(1) register を明示的に宣言したブロックスコープ変数、または static または extern を明示的に宣言しなかったブロックスコープ変数には、自動ストレージ期間があります。これらのエンティティのストレージは、エンティティが作成されたブロックが終了するまで続きます。

[...]

(3) 自動保存期間を持つ変数に初期化または副作用のあるデストラクタがある場合、そのブロックの終了前に破棄してはならず、未使用のように見えても最適化として削除してはなりません。クラス オブジェクトまたはそのコピー/移動は、12.8 で指定されているように削除できます。

これが意味することは、Aそれが宣言されているブロックが終了すると、その存続期間が終了するということです。の場合func1、これは return-statement の後です。その場合はfunc3return-statement の前です。

(「ブロック」とは、中括弧で囲まれたコードの一部です: {...}.)

したがって、func1のデストラクタAが呼び出される前に戻り値を評価し、 を返します3func3デストラクタが呼び出された後に戻り値を評価するため、 が返されます10

の場合はfunc2と同じ順序ですがfunc1、参照を返すため、 のデストラクタによる値の変更Aは、戻り値の評価後に行われたとしても、元の値に影響を与えます。戻ってきた。

于 2013-06-28T02:05:17.647 に答える
2

A デストラクタが呼び出される前に、 i のコピーまたはそれへの参照を返すかどうかに関係しています。

func1() ケース:

  1. 私は3に設定されています
  2. i の値は、i のコピーとして (一時的に) 返されます。
  3. i はデストラクタで 10 に設定されます
  4. i (3) のコピーが印刷されます

func2() ケース:

  1. 私は8に設定されています
  2. i の値は、グローバル変数 i への参照として返されます
  3. i はデストラクタで 10 に設定されます
  4. i の現在の値が出力されます

func3() ケース:

  1. 私は8に設定されています
  2. i はデストラクタで 10 に設定されます
  3. i の値はコピーとして返されます
  4. i (10) のコピーが印刷されます
于 2013-06-28T02:08:06.060 に答える
0

デストラクタは、return ステートメントの後、呼び出し関数の次の行の前に発生します。戻り値は隠し変数に保存され、次にデストラクタとその他の関数のクリーンアップが呼び出され (スタックを返すなど)、呼び出し元で実行が続行されます。

さらに明確にするために、戻り行が だったと想像してくださいreturn i+A.foo();。この行の後までデストラクタを呼び出したくないでしょう。さもなければ、A は foo を呼び出すのに有効ではありません。これが、リターンの後にデストラクタが常に呼び出される理由です。

于 2013-06-28T01:57:49.067 に答える