Насколько я понимаю, этот лямбда-вызов должен быть недействительным, но он не вылетает.Зачем? - PullRequest
0 голосов
/ 13 февраля 2019

У меня проблемы с пониманием, почему следующий код не дает сбоя.

class MyClass
{
public:
    MyClass() {    m_contents = 0xF0F0F0F0; }
    void Hello() { printf("Hello, address: %llx, contents: %x, size: %d\n", (long long int)this, m_contents, sizeof(MyClass)); }
    int m_contents;
};

int main()
{
    MyClass* MyObj = new MyClass();
    MyObj->Hello();

    auto MyLambda = [MyObj]()
    {
        if (MyObj != nullptr)
        {
            MyObj->Hello();
        }
    };

    memset(MyObj, 0, sizeof(MyClass));
    MyObj->Hello();
    delete MyObj;
    MyObj = nullptr;

    MyLambda();

    return 0;
}

Это вывод:

Hello, address: 1ddb4a16100, contents: f0f0f0f0, size: 4
Hello, address: 1ddb4a16100, contents: 0, size: 4
Hello, address: 1ddb4a16100, contents: dddddddd, size: 4

Я бы ожидал сбоя лямбда-вызова, потому что я уничтожил всю память, используемую для вызова функции Hello (),Я знаю, что содержимое стирается, потому что m_contents становится 0. После вызова delete m_contents становится случайным значением, но все равно вызывается Hello (), и сбоя не происходит.

Последующий вопрос: В лямбде, где я передаю этот в качестве захвата, есть ли вероятность, что этот станет нулевым или недействительным к тому времени, когда лямбда будет вызвана

1 Ответ

0 голосов
/ 13 февраля 2019

[MyObj]() { } захватывает указатель MyObj не по ссылке, а по значению.Это означает, что значение MyObj будет скопировано во время создания лямбды.Таким образом, даже после того, как вы установите MyObj в nullptr, лямбда все равно будет использовать свое первоначальное значение, которое все еще будет указывать на ту же область в памяти.

В то время, когда вы вызываете лямбду, объект в *MyObjуже был удален, что видно по всем 0xdd байтам (по крайней мере, в режиме отладки).

Если вы напишите [&MyObj]() { }, тогда MyObj будет записано как ссылка, что означаетлямбда всегда будет использовать текущее значение захваченного указателя.В этом случае поведение должно быть в точности таким, как вы ожидали, во-первых: проверка nullptr в вашей лямбде не удалась бы и Hello() не была бы вызвана.

Что касается вашего следующего вопроса: Passing this работает не отличается от любого другого символа.Передача его по значению создаст копию, которая всегда позволит вам получить доступ к объекту, даже после его срока службы (со всеми вытекающими отсюда рисками).Передача по ссылке будет работать до тех пор, пока указатель действителен, что, вероятно, будет продолжаться до тех пор, пока область действия метода действительна.

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