C ++ 11 лямбда-выражений: получение переменной-члена - PullRequest
40 голосов
/ 14 октября 2011

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

#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()

Вопрос:

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

1 Ответ

40 голосов
/ 14 октября 2011

Это поведение определяется стандартом

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...