web-dev-qa-db-ja.com

ローカルCスタイルの配列からポインターを返すことにより、ぶら下がりポインターを取得する

私は次のコードに少し混乱しています。

#include <iostream>

const char* f()
{
    const char* arr[]={"test"};
    return arr[0];
}

int main()
{
    auto x = f();
    std::cout << x;
}

私の意見では、このコードはUB(未定義の動作)でなければなりません。ローカルスコープ内のCスタイルの配列要素へのポインターを返します。物事はうまくいかないはずです。しかし、私がテストしたコンパイラは文句を言いません(私は-Wall -Wextra -pedantic g ++とclangの両方で)。 valgrindも文句を言いません。

上記のコードは有効ですか、それともUBは考えているでしょうか?

PS:実行すると「正しい」結果、つまり「テスト」が表示されるように見えますが、それは正確性を示すものではありません。

48
vsoftco

いいえ、それはUBではありません。

この:

const char* f()
{
    const char* arr[]={"test"};
    return arr[0];
}

同等のものに書き換えることができます:

const char* f()
{
    const char* arr0 = "test";
    return arr0;
}

したがって、文字列リテラルへのローカルポインターを返すだけです。文字列リテラルには 静的な保存期間 があり、ぶら下がることはありません。機能は実際には次と同じです。

const char* f()
{
    return "test";
}

thisのようなことをした場合:

const char* f() {
    const char arr[] = "test"; // local array of char, not array of char const*
    return arr;
}

これでthatはUBです-ダングリングポインターを返しています。

77
Barry

配列arrにはローカルストレージ期間があり、スコープの終わりに消えます。ただし、文字列リテラル"test"は、静的な保存場所へのポインターです。このポインターを返す前に、ローカル配列arrに一時的に保存しても変更されません。常に静的な保管場所になります。

関数がCスタイルconst char *の代わりにC++スタイルの文字列型を返す場合、追加の変換/ブックキーピングにより、C++の一時的な規則に従ってライフタイムが制限される可能性があります。

3
user9594869