17

次のサンプル コードを考えます。

int main()
{
    int i;
    auto f = [=]()mutable->int*
    {
            return &i;
    };

    return 0;
}
  1. g++ v.4.8.1 は、「ローカル変数 'i' のアドレスが返されました」と警告します。
  2. Clang v.3.2 (MacOS の Clang) は、「ローカル変数 'i' に関連付けられたスタック メモリのアドレスが返されました」と警告します。
  3. VS2012 も VS2013 RC も何も警告しません。

ラムダについての私の理解は、コンパイラーがファンクタークラスを生成するということです。そのファンクター クラスには、コピーされたすべての変数のメンバーが含まれます (i例では)。私のコードのコンテキストでは、f存在する限り、そのメンバーの 1 つのアドレスを返すことは安全だと思います。すべてのコンパイラが間違っているようです。がスコープ外になった後にfのメンバーのアドレスを使用することに関する警告は有効だと思いますが、「ローカル変数 'i'」に関する警告は正しくない/誤解を招くものです。私は正しいですか?if

4

2 に答える 2

4

いくつかの用語:

  • =または&内部[&](){ /*..*/ }は、 capture-default と呼ばれます
  • 変数の ODR 使用とは、変数が破棄値式 ((void)some_variableまたは などint x = some_variable, 5;) に出現せず、定数式にも出現しないことを大まかに意味します。
  • 複合ステートメントは「機能ブロック」{ ステートメントです }
  • 変数の名前はid-expressionです

[expr.prim.lambda]/3

ラムダ式の型(クロージャー オブジェクトの型でもあります) は、名前のない一意の非共用体クラス型 —クロージャー型と呼ばれます — のプロパティについては、以下で説明します。

/11

ラムダ式に関連付けられた capture-defaultとその複合ステートメントodr-uses (3.2)thisまたは自動保存期間を持つ変数があり、odr-used エンティティが明示的にキャプチャされていない場合、odr-used エンティティは暗黙的にキャプチャされます。

したがって、i暗黙的にキャプチャされます。

/14

エンティティが暗黙的にキャプチャされ、capture-default が である=場合、または を含まないキャプチャで明示的にキャプチャされた場合、エンティティはコピーによってキャプチャされます&。コピーによってキャプチャされたエンティティごとに、名前のない非静的データ メンバーがクロージャー型で宣言されます。

intクロージャー型に非静的データ メンバー (型) があります。

/17

コピーによってキャプチャされたエンティティの ODR 使用 (3.2) であるすべての id-expressionは、クロージャー型の対応する名前のないデータ メンバーへのアクセスに変換されます。

この段落はOPと非常によく似た例を提供するため、これを解釈する必要さえありません。

void f(const int*);
void g() {
    const int N = 10;
    [=] {
        int arr[N]; // OK: not an odr-use, refers to automatic variable
        f(&N);      // OK: causes N to be captured; &N points to the
                    // corresponding member of the closure type
    };
}

これを OP の例に適用すると、クロージャー型の内部の非静的データ メンバーを参照している&iことがわかります。診断メッセージが適切かどうかは、標準では指定されていません;)

于 2013-09-23T00:12:39.633 に答える