28

shared_from_this()インスタンスが存続することを保証するために、コールバックとしてラムダ式を使用するときにキャプチャに依存するかなりの量のコードがあります。

std::shared_ptr<Thing> self = shared_from_this();
auto doSomething = [this, self] ()
{
    // various statements, none of which reference self, but do use this
}

質問は次のとおりです。ラムダ本体の内部を参照していないのでself、適合コンパイラはキャプチャを最適化できますか?


次のプログラムを検討してください。

#include <functional>
#include <iostream>
#include <memory>

std::function<void ()> gFunc;

struct S : std::enable_shared_from_this<S>
{
    void putGlobal()
    {
        auto self = shared_from_this();
        gFunc = [self] { };
    }
};

int main()
{
    auto x = std::make_shared<S>();
    std::cout << x.use_count() << std::endl;
    x->putGlobal();
    std::cout << x.use_count() << std::endl;
}

出力は次のとおりです。

1
2

これはg++-4.7.1、キャプチャを最適化しないことを示しています(また、最適化しませんclang-3.1)。

4

1 に答える 1

34

標準は、キャプチャされた値が最適化されないことを保証します(§5.1.2/ 14に従って):

エンティティが暗黙的にキャプチャされ、capture-defaultが=である場合、または&を含まないキャプチャで明示的にキャプチャされている場合、エンティティはコピーによってキャプチャされます。コピーによってキャプチャされたエンティティごとに、名前のない非静的データメンバーがクロージャタイプで宣言されます。これらのメンバーの宣言順序は指定されていません。このようなデータメンバーのタイプは、エンティティがオブジェクトへの参照でない場合は対応するキャプチャされたエンティティのタイプであり、そうでない場合は参照されるタイプです。

したがって、self評価時にクロージャにコピーされます(§5.1.2/ 21による):

ラムダ式が評価されると、コピーによってキャプチャされたエンティティが、結果のクロージャオブジェクトの対応する非静的データメンバーを直接初期化するために使用されます。

于 2012-10-03T23:42:41.290 に答える