1

以下のコードを考えると、コンパイラーはwarning C4172: returning address of local variable or temporary関数 f1() および f2() に対して出力しますが、f3() に対しては出力しません。以下の関数 f3() の場合のように、特定の状況ではコンパイラがこの問題を特定できない場合があることを理解しています。しかし、この場合、警告メッセージなしで正しい診断を確認するにはどうすればよいでしょうか?

const char* const& f1() { return "hello1"; }
const char* const& f2() { return static_cast<const char*>("hello2"); }
const char* const& f3() { const char* const& r = "hello3"; return r; }
4

2 に答える 2

3

私は、3 つの関数すべてに未定義の動作があると確信しています。

f3UB (またはf1/でさえ)ではないと主張する人々へf2: このコードを実行してみてください:

#include <iostream>

const char* const& f1() { return "hello1"; }
const char* const& f2() { return static_cast<const char*>("hello2"); }
const char* const& f3() { const char* const& r = "hello3"; return r; }

int main()
{
    using namespace std;

//#define F f1
//#define F f2
#define F f3

    const char* const& ret = F();
    cerr << ret;
    cerr << ",";
    cerr << ret;

    return 0;
}

(私はすぐにフラッシュするのcerrではなく、を使用しました。の2番目の出力の後にa に変更して追加できます。)coutcerrcoutcout << flush;ret

私のGCCで私が印刷したものは次のとおりです。

  • with f1: hello1,8??q?(コンマの後のいくつかのランダムな文字)
  • with f2: hello2,8j?y5(コンマの後のいくつかのランダムな文字)
  • with f3: hello3,,(コンマの後の 2 つ目のコンマ)

それは私にはUBに非常に似ています...

(注:どちらかを削除するconst&と、「機能します」。const&実際に削除するのは、もちろん戻り型のものです。)

f3それは、次のようなことが起こっているからだと思います。

const char* const& f3()
{
    const char* __tmp001 = &("hello3"[0]); // "array decaying"
    const char* const& r = __tmp001;
    return r;
}

実際、文字列リテラル"hello3"はaではなくconst char*、 (static)const char [7]です。コードconst char* const& r = "hello3";では、参照をこの char 配列に直接バインドすることはできません。これは、型が同じではないためです。そのため、コンパイラは、暗黙な変換 (配列からポインターへの参照がバインドされている ( demo )。このテンポラリconst char*の有効期間は、参照の有効期間まで「延長」されるためr、最初のセミコロンでは終了しませんが、関数が戻ると終了します ( demoおよびすべての最適化をオフにした出力)。したがって、 「ダングリング参照」f3を返します. 私のテスト出力コードでは、スタックを上書きする後続の操作により、UB が表示されます。

jalf のコメントの後に編集:「2 番目の出力でガベージを出力する」ことは UB の証明ではないことを意識しています。UB を使用したプログラムは、期待どおりに動作することも、クラッシュすることも、何もしないこともできます。しかし、それにもかかわらず、明確に定義されたプログラム(UBなし)がそのようなゴミを出力するとは思いません...

于 2013-07-01T20:37:24.573 に答える