2013-03-25 18 views
7

Supponiamo di avere il seguente.Espressione lambda che cattura di nascosto `this`

struct A 
{ 
    int x; 
    std::function<int()> f1() { return [=](){ return x; }; } 
    std::function<int()> f2() { return [=](){ return this->x; }; } 
    std::function<int()> f3() { return [this](){ return x; }; } 
    std::function<int()> f4() { return [this](){ return this->x; }; } 
    std::function<int()> f5() 
    { 
     int temp = x; 
     return [=](){ return temp; }; 
    } 
} 

E ora ho il seguente codice.

auto a = std::make_shared<A>(); 
a->x = 5; 
std::function<int()> f = a.f#(); 
a.reset(); 
int x = f(); 

dove il f# indicato si intende qualsiasi f1, f2, f3, f4, f5.

Queste funzioni espongono comportamento in uno dei due insiemi:

  1. ritorno 5 quando chiamato (f5), o
  2. arrestato tentativo di dereference nullptr (f1, f2, f3, f4).

Capisco che questo è perché alcuni sono cattura "this" nella funzione di membro del A, implicitamente o esplicitamente.

Qual è la regola formale che determina il comportamento 1 o 2?

ho trascorso un po 'di fronte ad un bug che è stato causato da qualcosa di simile a f1, pensando che sarebbe catturare x e mai considerando che sarebbe catturare this, così ho pensato che sarebbe stato utile per ottenere questo documentato.

risposta

8

Non esiste una regola formale che determina questo comportamento. Perché questo comportamento è non definito.

I tuoi lambda stanno accedendo a un oggetto che non esiste. Non è possibile acquisire una variabile membro direttamente per valore; li catturi sempre per this. Il che significa che li stai catturando per riferimento. Una volta eliminato l'oggetto, qualsiasi tentativo di accedere a quell'oggetto eliminato comporta un comportamento indefinito.

L'eccezione è f5, che dovrebbe restituire un valore coerente, garantito. È completamente disconnesso dall'oggetto di origine.

+0

Oh - Ho etichettato i gruppi 'f1, f2, f3, f4' e' f5' all'indietro! Sì, volevo dire che 'f5' funziona correttamente e gli altri no. Modificato. –