28

私は c++ からやり直し、変数のスコープについて考えていました。関数内に変数があり、その変数を返す場合、その変数は、スコープが終了したために返されたときに「死んで」いませんか?

文字列を返す関数でこれを試してみましたが、うまくいきました。誰でもこれを説明できますか?または、少なくともこれを説明できる場所を教えてください。

ありがとう

4

6 に答える 6

48

関数が終了すると、次の手順が実行されます。

  • 関数の戻り値は、この目的のためにスタックに置かれたプレースホルダーにコピーされます。

  • スタック フレーム ポインタの後のすべてがポップ オフされます。これにより、すべてのローカル変数と引数が破棄されます。

  • 戻り値はスタックからポップされ、関数の値として割り当てられます。関数の値が何にも割り当てられていない場合、割り当ては行われず、値は失われます。

  • 次に実行する命令のアドレスがスタックからポップされ、CPU はその命令で実行を再開します。

スタックとヒープ

于 2008-11-08T21:26:28.817 に答える
4

値を返すと、コピーが作成されます。ローカル変数のスコープは終了しますが、コピーが作成され、呼び出し元の関数に返されます。例:

int funcB() {
  int j = 12;
  return j;
}

void A() {
  int i;
  i = funcB();
}

j の値 (12) がコピーされて i に返されるため、i は 12 の値を受け取ります。

于 2008-11-08T21:23:50.570 に答える
4

それは、返す変数の種類によって異なります。プリミティブを返す場合、それは参照ではなくコピーによって返されるため、値は呼び出し元の関数が取得できるスタックの一番上にコピーされます (または、より多くの場合、レジスタに配置されます)。オブジェクトまたはメモリをヒープに割り当ててポインターを返す場合、スタックではなくヒープ上にあるため、ポインターは死ぬことはありません。ただし、スタックに何かを割り当ててそれを返すと、それは悪いことです。たとえば、次のいずれかは非常に悪いものです。

int *myBadAddingFunction(int a, int b)
{
    int result;

    result = a + b;
    return &result; // this is very bad and the result is undefined
}

char *myOtherBadFunction()
{
    char myString[256];

    strcpy(myString, "This is my string!");
    return myString; // also allocated on the stack, also bad
}
于 2008-11-08T21:25:29.597 に答える
3

もう少しメモリモデル指向の説明のために: 関数が呼び出されると、関数がそのローカル変数を配置するための一時的なスペースが作成され、これはframeと呼ばれます。関数 (呼び出し先) が値を返すと、それを呼び出した関数 (呼び出し元) のフレームに戻り値を配置し、呼び出し先のフレームを破棄します。

「フレームが破棄される」部分が、関数からローカル変数へのポインターまたは参照を返すことができない理由です。ポインターは実質的にメモリ ロケーションであるため、フレームが破棄されると、ローカル変数 (定義上、フレーム内の変数) のメモリ ロケーションが正しく返されなくなります。呼び出し先フレームは値を返すとすぐに破棄されるため、ローカル変数へのポインターまたは参照はすぐに正しくなくなります。

于 2008-11-08T21:37:29.760 に答える
2

これは、返品されたアイテムの種類によって異なります。値で返す場合は、変数の新しいコピーが作成され、呼び出し元に返されます。オブジェクトの有効期間について心配する必要はありませんが、オブジェクトをコピーするコストについて心配する必要があるかもしれません (ただし、時期尚早に最適化しないでください - 正確性がはるかに重要です)。

std::string someFunc( std::string& const s)
{
    return s + "copy";
}

関数が参照を返す場合、その有効期間は関数の有効期間を超えて延長する必要があり、オブジェクトの作成にdelete使用している場合、呼び出し元が必ずしもそれを実行できるとは限らないため、返すものに注意する必要があります。new

std::string& someFunc2( std::string const& s)
{
    return s + "reference to a copy";   // this is bad - the temp object created will 
                                        //  be destroyed after the expression the 
                                        //  function call is in finishes.
                                        //  Some, but not all, compilers will warn 
                                        //  about this.
}

もちろん、ポインターを返す場合も同様の有効期間の考慮事項があります。

于 2008-11-09T00:32:39.890 に答える
2

ローカル変数は戻り値にコピーされます。コピー コンストラクターは、重要なクラスに対して呼び出されます。

ローカル変数へのポインターまたは参照を返すと、直観が示唆したように、問題が発生します。

于 2008-11-08T21:21:15.660 に答える