С++: Может ли оптимизироваться неиспользуемый ямбда-ямба?

У меня есть достойный код, который полагается на захват 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).

Ответ 1

Стандарт гарантирует, что зафиксированные значения не будут оптимизированы (в §5.1.2/14):

Объект захватывается копией, если он неявно захвачен, а значение по умолчанию - = или if явно захвачен с захватом, который не включает &. Для каждого объекта, захваченного копией, статический член данных объявляется в типе замыкания. Порядок объявления этих членов не указан. Тип такого элемента данных является типом соответствующего захваченного объекта, если объект не является ссылку на объект или ссылочный тип в противном случае.

Итак, self копируется в замыкание при оценке (согласно § 5.1.1.2/21):

Когда вычисляется лямбда-выражение, объекты, которые захватываются копией, используются для прямой инициализации каждый соответствующий нестатический элемент данных результирующего объекта замыкания.