47

主な質問

GCC 4.7.2 で次のコードをコンパイルしようとしています。

#include <iostream>

int foo() {
    static int bar;
    return [&bar] () { return bar++; } (); // lambda capturing by reference
}

int main (int argc, char* argv[]) {
    std::cout << foo() << std::endl;
    return 0;
}

そして、出力が次のようになるため、うまくいかないようです。

$p2.cpp: In function ‘int foo()’:
$p2.cpp:6:14: warning: capture of variable ‘bar’ with non-automatic storage duration [enabled by default]
$p2.cpp:4:16: note: ‘int bar’ declared here

したがって、私の最初の質問は次のようになります。

これは GCC の失敗ですか、それともコードは正当な C++11 ではありませんか? これは GCC の最近のバージョンで修正されていますか?

shared_ptr ファクトリでのトリックの使用

この原則に基づいてアーティファクトを構築することを検討していますが、リテラルではない静的変数を使用しています。このアーティファクトは、shared_ptr< T > オブジェクトのファクトリであることを意図しており、同じインスタンスに対して重複する shared_ptr コンテナーが必要な場合に、新しい T オブジェクトの作成を回避します。

このアーティファクトは次のようになります。

std::shared_ptr<Foo> create(std::string name) {
    static std::unordered_map<std::string,std::weak_ptr<Foo>> registry;

    if (auto it = registry.find(name) != registry.end())
        return registry[name].lock();

    auto b = std::shared_ptr<Foo>(
        new Foo(name), 
        [&registry] (Foo* p) {
            registry.erase(p->getName());
            delete p;
        });

    registry.emplace(name,b);
    return b;
}

私の知る限り、前に説明した GCC の問題が C++11 への準拠に関して問題にならない場合、このアーティファクトも問題にならないはずです。このハックを使用する際に注意すべき唯一のことは、結果の shared_ptr< T > オブジェクトを、静的変数の後に破棄される可能性のあるグローバル オブジェクトに設定しないことです。

私はこれについて正しいですか?

4

2 に答える 2

101

なぜあなたはキャプチャしようとしているのbarですか?静的です。キャプチャする必要はまったくありません。自動変数のみキャプチャが必要です。Clang は、警告だけでなく、コードにハード エラーをスローします。また、ラムダ キャプチャから を削除するだけ&barで、コードは完全に機能します。

#include <iostream>

int foo() {
    static int bar;
    return [] () { return bar++; } (); // lambda capturing by reference
}

int main (int argc, char* argv[]) {
    std::cout << foo() << std::endl;
    std::cout << foo() << std::endl;
    std::cout << foo() << std::endl;
    return 0;
}

版画

0
1
2
于 2012-12-11T20:24:49.090 に答える
13

標準では、自動保存期間 (またはthis、明示的にキャプチャ可能であると言及されている) を持つ変数のみをキャプチャできます。

したがって、いいえ、標準に従ってそれを行うことはできません (または、最初の質問に答えるために、それは有効な C++ 11 ではなく、コンパイラのバグではありません)。

5.1.1/2 lambda-capture 内の名前は、ラムダ式のコンテキストの範囲内にあり、これであるか、ローカル変数を参照するか、自動保存期間を使用して参照する必要があります。

static編集:そして、ケビンが述べたように、とにかくローカルをキャプチャする必要さえありません.

于 2012-12-11T20:38:26.200 に答える