19

重複の可能性:
一時的なものの寿命

int LegacyFunction(const char *s) {
    // do something with s, like print it to standard output
    // this function does NOT retain any pointer to s after it returns.
    return strlen(s);
}

std::string ModernFunction() {
    // do something that returns a string
    return "Hello";
}

LegacyFunction(ModernFunction().c_str());

上記の例は、文字列の代わりにスマートポインタを使用するように簡単に書き直すことができます。私はこれらの状況の両方に何度も遭遇しました。とにかく、上記の例では、ModernFunctionでSTL文字列を作成して返し、文字列オブジェクト内のCスタイルの文字列へのポインタを取得して、そのポインタをレガシー関数に渡します。

  1. ModernFunctionが戻った後に存在する一時的な文字列オブジェクトがあります。いつ範囲外になりますか?
  2. コンパイラがc_str()を呼び出し、この一時文字列オブジェクトを破棄してから、ダングリングポインタをLegacyFunctionに渡すことは可能ですか?(文字列オブジェクトは、c_str()の戻り値が指すメモリを管理していることに注意してください...)
  3. 上記のコードが安全でない場合、なぜ安全ではないのでしょうか。また、関数呼び出しを行うときに一時変数を追加するよりも、同じように簡潔な方法でコードを記述できるのでしょうか。安全だとしたら、なぜですか?
4

2 に答える 2

15
LegacyFunction(ModernFunction().c_str());

コピーの破棄は、評価full expression後(つまり、から戻った後LegacyFunction)に行われます。

n3337 12.2 / 3

一時オブジェクトは、それらが作成されたポイントを(字句的に)含む完全式(1.9)を評価する最後のステップとして破棄されます。

n3337 1.9 / 10

完全式は、別の式の部分式ではない式です。関数の暗黙的な呼び出しを生成するように言語構造が定義されている場合、言語構造の使用は、この定義の目的のための式と見なされます。一時オブジェクト以外のオブジェクトの存続期間の終わりに生成されたデストラクタの呼び出しは、暗黙の完全式です。式が表示される言語構造の要件を満たすために式の結果に適用される変換も、完全な式の一部と見なされます。[ 例:

struct S {
S(int i): I(i) { }
int& v() { return I; }
private:
int I;
};
S s1(1); // full-expression is call of S::S(int)
S s2 = 2; // full-expression is call of S::S(int)
void f() {
if (S(3).v()) // full-expression includes lvalue-to-rvalue and
// int to bool conversions, performed before
// temporary is deleted at end of full-expression
{ }
}

于 2012-09-07T17:57:05.633 に答える
9

ModernFunctionが戻った後に存在する一時的な文字列オブジェクトがあります。いつ範囲外になりますか?

厳密に言えば、それは決して範囲内ではありません。スコープは名前のプロパティであり、オブジェクトではありません。自動変数がスコープライフタイムの間で非常に密接に関連しているのはたまたまです。自動変数ではないオブジェクトは異なります。

一時オブジェクトは、ここでは関係のないいくつかの例外を除いて、それらが表示される完全な式の最後で破棄されます。とにかく、特別な場合は一時的なものの寿命を延ばします、彼らはそれを減らしません。

コンパイラがc_str()を呼び出し、この一時文字列オブジェクトを破棄してから、ダングリングポインタをLegacyFunctionに渡すことは可能ですか?

いいえ、完全な式はLegacyFunction(ModernFunction().c_str())(セミコロンを除く:その衒学者を感じます)であるため、の戻り値である一時的なものは、が戻るModernFunctionまで破棄されませんLegacyFunction

安全だとしたら、なぜですか?

一時的なものの寿命が十分に長いからです。

一般的にc_str、では、2つのことを心配する必要があります。まず、文字列が破棄されると、返されるポインタが無効になります(これがあなたが求めているものです)。次に、文字列が変更されると、返されるポインタが無効になります。ここではそれについて心配していませんが、文字列を変更するものがないため、心配する必要はありません。

于 2012-09-07T18:01:32.443 に答える