3

参照: C++ テンプレートのコード スニペット: 完全ガイド

// maximum of two values of any type (call-by-reference) 
template <typename T> 
inline T const& max (T const& a, T const& b) 
{ 
    return a < b ? b : a; 
} 

// maximum of two C-strings (call-by-value) 
inline char const* max (char const* a, char const* b) 
{ 
    return std::strcmp(a,b) < 0 ? b : a; 
} 

// maximum of three values of any type (call-by-reference) 
template <typename T> 
inline T const& max (T const& a, T const& b, T const& c) 
{ 
    return max (max(a,b), c); // error, if max(a,b) uses call-by-value 
} 

int main () 
{ 
    ::max(7, 42, 68); // OK 

    const char* s1 = "frederic"; 
    const char* s2 = "anica"; 
    const char* s3 = "lucas"; 
    ::max(s1, s2, s3); // ERROR 

} 

上記のコードについて述べられている問題:

問題は、3 つの C 文字列に対して max() を呼び出すと、次のステートメントが

リターンマックス(マックス(a、b)、c); エラーになります。これは、C 文字列の場合、max(a,b) が参照によって関数によって返される可能性のある新しい一時的なローカル値を作成するためです。

質問> 上記の点についてまだ理解できていません。どうして

「引数が 3 つのバージョンを使用して、最大 3 つの C 文字列を計算することはできません」?

// アップデート

const int* fReturnValue(const int *i)
{
    return i;
}

int main()
{
    int i = 3;
    const int* i4= fReturnValue(&i);

    cout << &i << endl;
    cout << i4 << endl;
}

観察: 両方の行が同じアドレスを返します。したがって、関数 fReturnValue では、関数は値によって返されますが、ポインターアドレスである b/c を損なうことはないと思います。つまり、リターン アドレスは引き続き有効です。

本当?

4

1 に答える 1

11

問題は、 のC 文字列フレーバーがmax値渡しであり、引数を値渡しするほどではないことです。一般的な 3 ウェイmax関数は参照を返すように宣言されていますが、C 文字列 maxは値を返します。その結果、一時オブジェクトへの参照が返され、アクセスする前に死んでしまいます。

更新:追加した新しいコードは、元の問題と同等ではありません。これは次のようになります。

const int*& fReturnValue(const int *i)
{
    return i;
}

は、関数が戻るまでに有効期間が終了するfReturnValueローカル変数への参照を返すことに注意してください。iそのため、関数は無効なオブジェクトへの参照を返します。その変更を加えてコードをコンパイルしてみてください。ほぼすべてのコンパイラから警告が表示されるはずです。

于 2013-02-20T20:50:27.507 に答える