Подтвердить что ты не робот

С++ 11 lambdas: захват переменной элемента getcha

Рассмотрим этот код:

#include <memory>
#include <iostream>

class A
{
public:
    A(int data) : data_(data)
    { std::cout << "A(" << data_ << ")" << std::endl; }
    ~A() { std::cout << "~A()" << std::endl; }
    void a() { std::cout << data_ << std::endl; }
private:
    int data_;
};

class B
{
public:
    B(): a_(new A(13)) { std::cout << "B()" << std::endl; }
    ~B() { std::cout << "~B()" << std::endl; }
    std::function<void()> getf()
    {
        return [=]() { a_->a(); };
    }
private:
    std::shared_ptr<A> a_;
};

int main()
{
    std::function<void()> f;
    {
        B b;
        f = b.getf();
    }
    f();
    return 0;
}

Здесь, похоже, я захватываю a_ общий указатель по значению, но когда я запускаю его в Linux (GCC 4.6.1), это печатается:

A(13)
B()
~B()
~A()
0

Очевидно, что 0 неверно, поскольку A уже уничтожен. Похоже, что this фактически захвачен и используется для поиска this->a_. Мое подозрение подтверждается, когда я меняю список захвата с [=] на [=,a_]. Затем печатается правильный вывод, а срок службы объектов - как ожидалось:

A(13)
B()
~B()
13
~A()

Вопрос:

Является ли это поведение указанным стандартом, определенным реализацией или undefined? Или я сумасшедший, и это нечто совсем другое?

4b9b3361

Ответ 1

Является ли это поведение стандартным

Да. Захват переменных-членов всегда выполняется путем захвата this; это единственный способ получить доступ к переменной-члену. В рамках функции-члена a_ эквивалентно (*this).a_. Это справедливо и в Лямбдасе.

Следовательно, если вы используете this (неявно или явно), вы должны убедиться, что объект остается в живых, когда экземпляр лямбда находится вокруг.

Если вы хотите записать его по значению, вы должны явно сделать это:

std::function<void()> getf()
{
    auto varA = a_;
    return [=]() { varA->a(); };
}

Если вам нужна спецификация:

Компонент-оператор лямбда-выражений дает тело функции (8.4) оператора вызова функции, но для целей поиска по имени (3.4), определяя тип и значение этого (9.3.2) и преобразуя id- выражения, относящиеся к нестационарным членам класса, в выражения доступа к члену класса, используя (* this) (9.3.1), составной оператор рассматривается в контексте лямбда-выражения.