2013-10-09 18 views
5

Pracuję nad aplikacją intensywnie wykorzystującą pamięć, która powinna odpowiednio obsługiwać sytuacje braku pamięci.Gdzie przechowuje się przechwycone zmienne zamknięcia?

Mam coś jak

class memory_manager { 
    // returns true if slot created (and function is being run) 
    // false otherwise 
    static bool create_slot(int id, std::function<void (slot&)>); ........ 
} 

obsługuje tej klasy, dzienniki, i tak na wszystkich out-of-memory kwestii, zachowuje własność wszystkich gniazdach i dysków współbieżności.

Mam jednak nieobsługiwany std::bad_alloc na następujący kod:

slot_data_to_copy dat; 

memory_manager::create_slot(100, [&dat](slot& sx) { sx.assign_data(dat); }); 

Zakładam, że rzut odbywa się podczas przechwytywania zmienne. (Przechwytywam ich więcej, to tylko przykładowy przykład)

Gdzie jest utworzone zamknięcie? Czy mogę to kontrolować? Lub, jeśli zaktualizuję menedżera w taki sposób, że przyjmuje on parametr, taki jak

slot_data_to_copy dat; 

memory_manager::create_slot<slot_data_to_copy> 
     (100, dat, [](slot& sx, slot_data_to_copy& dat) 
      { sx.assign_data(dat); } 
     ); 
czy ma pewność, że w ogóle go nie rzuci?

Kompiluję oba przy użyciu Visual C++ na Windows i GCC na Linuksie, ale obserwowałem to zachowanie tylko w systemie Windows (na Linuksie, zabrakło pamięci prawdopodobnie gdzieś, gdzie mogę sobie z tym poradzić).

EDIT:

http://en.cppreference.com/w/cpp/utility/functional/function/function - std :: funkcja zawiera nothrow operatorów .. ja chyba czegoś brakuje, ale który z nich jest używany w tej sytuacji (lambda)?

+0

'Zakładam, że rzut jest wykonywany podczas przechwytywania zmiennych. '- lambda jest kopiowana na stercie? i, kiedy zostanie wydany? – nothrow

+1

[expr.prim.lambda]/2 "Ocena wyrażenia lambda skutkuje tymczasową prwartością, która jest nazywana * obiektem zamknięcia *." Ctor 'std :: function', który jest tu używany, to' template < class F > function (F f); ', który jest * nie *' noexcept'. – dyp

Odpowiedz

4

Gdzie jest utworzone zamknięcie?

Wyrażenie lambda tworzy obiekt o nienazwanym typie, który jest zwykłą klasą funktora. Przechwycone zmienne są członkami tego nienazwanego typu.

Kod memory_manager::create_slot(100, [&dat](slot& sx) { sx.assign_data(dat); }); jest zasadniczo taka sama, jak:

slot_data_to_copy dat; 

struct unnamed_lambda_type { 
    slot_data_to_copy &dat; 

    unnamed_lambda_type(slot_data_to_copy &dat_) : dat(dat_) {} 

    void operator() (slot &sx) const { 
    sx.assign_data(dat); 
    } 
}; 

memory_manager::create_slot(100, unnamed_lambda_type(dat)); 

Gdzie jest zamknięcie stworzył?

Obiekt zamknięcia jest jak każdy inny obiekt tymczasowy, zwykle przydzielany na stosie.

1

Zamknięcie to lambda; przechwycone zmienne są elementami danych anonimowej struktury (to jest wartość lambda). Tworzenie twojego lambda nie może rzucić bad_alloc; twój błąd jest gdzie indziej (prawdopodobnie tworząc std::function, który może kopiować lambda na stertę).

Sidenote: przechwytujesz przez odniesienie w swoim lambda; upewnij się, że twój slot_data_to_copy dat nie zostanie zniszczony przed wywołaniem lambda. Powinieneś skopiować go według wartości lub natychmiast zadzwonić do lambda.

+0

OK, założyłem, że rzut jest wykonywany podczas przechwytywania zmiennych (jeśli jest wykonywany w std :: function <> creation, nie mam nic przeciwko). Chciałbym, aby funkcja std :: była tworzona na stosie, czy byłoby to możliwe? – nothrow

+0

Funkcja 'std :: function' jest przekazywana jako parametr, więc jest już na stosie. 'std :: function' wewnętrznie ma wskaźnik do lambda na stercie (pomyśl jak' std :: vector' może być na stosie, ale jego dane są na stercie). – Simple

+0

ad sidenote - funkcja create_slot nie zachowuje lambda w dowolnym miejscu, więc dane nie mogą zostać zniszczone – nothrow

Powiązane problemy