1

重複の可能性:
ローカル変数のメモリにそのスコープ外でアクセスできますか?

コードレビューをしているときに関数を見ました。

wchar_t* GetString(HINSTANCE hInstance, UINT SID)
{
    wchar_t buf[2048] = {0}; 
    LoadStringW(hInstance, SID, buf, sizeof(buf)/sizeof(wchar_t));
    return &buf[0];
}

void SomeWork()
{
    std::wstring str( GetString(hInst, 123) );
}

関数 return の直後にbufを破棄する必要があると思っていたので、ポインタ &buf[0] が無効になっている可能性があります。しかし、それはうまくいくようです、それはどのように機能しますか?そして、それは素晴らしいデザインですか?ありがとう。

4

4 に答える 4

5

関数 return の直後にbufを破棄する必要があると思っていたので、ポインター&buf[0]が無効になっている可能性があります。

あなたの考えは100%正しいです。

しかし、それはうまくいくようです、それはどのように機能しますか?

buf配列を保持するコールスタックの部分は、実際に使用するまでにその内容が上書きされなかったため、「機能します」 。

しかし、これは未定義の動作であり、未定義の動作は何かが起こる可能性があることを意味し、「ハルマゲドンの召喚」および/または「正常に動作する」ことを含む可能性があります. 今回は運が良かっただけです。

そして、それは素晴らしいデザインですか?

いいえ、ひどいデザインです。std::wstring幸いなことに、これには簡単な修正があります。それ自体を返すだけです。

std::wstring GetString(HINSTANCE hInstance, UINT SID) 
{ 
    wchar_t buf[2048] = {0};  
    LoadStringW(hInstance, SID, buf, sizeof(buf)/sizeof(wchar_t)); 
    return std::wstring(buf);
} 

void SomeWork()   
{   
    std::wstring str = GetString(hInst, 123);   
}  

この場合、すべての愚かでない C++ コンパイラは一時変数を最適化するため、このコードは実際にはパフォーマンスの低下をもたらしません。実際、すべての最適化をオフにしても、Visual C++ コンパイラはこのケースを最適化します。

この特定の最適化は、戻り値の最適化 (RVO)と呼ばれます。最高の最適化レベルに設定しても C++ コンパイラが RVO を実行しない場合は、別のコンパイラを入手してください。

于 2012-09-05T07:04:46.857 に答える
3

いいえ、これは重大な欠陥です。ローカル オブジェクトへのポインタまたは参照を返すことは未定義の動作です。それは、第三次世界大戦の開始を含め、あらゆることが起こり得ることを意味します。あなたの場合、未定義の動作は「正常に動作する」のと同じです。運良く。

于 2012-09-05T07:04:53.863 に答える
1

関数 return の直後に buf を破棄する必要があると思っていたので、ポインタ &buf[0] が無効になっている可能性があります。

そのとおりです。の寿命bufは終わりました。そのメモリは、アクセスできなくなったり、別のオブジェクトに再利用されたりした可能性があります。それにアクセスすると、未定義の動作が発生します。

しかし、それはうまくいくようです、それはどのように機能しますか?

多くのプラットフォームでは、自動変数はスタックに格納されており、関数が戻ったときに関数のスタック メモリにアクセスできなくなることはありません。これは、別の関数を呼び出してメモリを再利用するまで、(無効なぶら下がり参照) 変数が古い値を保持しているように見えることが多いことを意味します。

そして、それは素晴らしいデザインですか?

確かにそうではありません。未定義の動作に依存しており、プラットフォームやコンパイラの変更、コードへの別の関数呼び出しの追加、または月の満ち欠けなど、さまざまな理由でコードが動作しているように見えなくなる可能性があります。

を返しますstd::wstring

于 2012-09-05T07:13:22.420 に答える
1

理論的に言えば、これは未定義の動作であり、(明らかに) 正しく動作することも含めて、あらゆることが起こり得ることを意味します。ただし、未定義であることは、常に機能することを保証する方法がないことを意味します。

現在動作しているように見える理由は、変更されたメモリが、GetStringそれを読み取るまでに実行されている他のコードによって変更されていないためです。言い換えれば、あなたは運が良かったのです。

于 2012-09-05T07:05:45.353 に答える