2012-11-01 15 views
20

Rozważmy następujący:Czy można bezpiecznie używać emplace_back z kontenerem unique_ptrs?

std::vector<std::unique_ptr<int>> ptrsToInts; 
ptrsToInts.emplace_back(new int); 

Jeżeli występuje przesunięcie w wektorze, a które nie (rzucanie std::bad_alloc), jestem „bezpieczne” lub będzie przeciekać się int?

C++ 11 23.3.6.5 [vector.modifiers]/1 mówi:

razie zgłaszany jest wyjątek inny sposób niż przez konstruktora kopii przesunąć konstruktor operatorowi przeniesienia lub przejść operatora Przyporządkowanie T lub przez dowolną operację InputIterator nie ma żadnych efektów.

co wydaje się wskazywać, że jest to potencjalny problem. Oznacza to, że jeśli istnieją "brak efektów", to nigdy nie skonstruowano żadnego unique_ptr, a zatem zachowanie destruktora polegałoby na delete, że wskaźnik nie wystąpiłby. (Co może oznaczać, że należy zablokować emplace_back dla pojemników unique_ptr s)

+1

Dobra uwaga. To zainspirowało mnie do porzucenia mojego używania "nowego" całkowicie na rzecz 'std :: make_unique', dzięki czemu mogę wiedzieć, że każdy przydział kończy się na inteligentnym wskaźniku od początku. – GManNickG

+0

Zauważyłem tę pułapkę w komentarzu tutaj: http://stackoverflow.com/questions/3283778/why-can-i-not-push-back-a-unique-ptr-into-a-vector/3283795#3283795 –

Odpowiedz

18

Jeśli wymagana jest realokacja i nie uda się, to tak, twój obiekt nigdy nie wszedł do pojemnika i dlatego zostanie utracony.

Należy jednak zauważyć, że jest to czysty błąd użytkownika. emplace_back nie powinno być "zakazane" dla kontenerów o numerze unique_ptr, ponieważ istnieją całkowicie bezpieczne sposoby na zrobienie tego (np. reserve ing przestrzeni wcześniej, więc wiesz, że zawsze będzie tam). Możesz także przekazać cały kod unique_ptr s, ponieważ jest on całkowicie zdolny do użycia konstruktora ruchu.

Naprawdę, twoja wina polega na tym, że nie prawidłowo zawijasz obiektu nie będącego RAII (int*) w obiekcie RAII przed punktem, w którym możesz zgłaszać wyjątki.

+2

Ah - ale obiekt nigdy tego nie zrobił. Emplacement konstruuje obiekt na miejscu wewnątrz samego bloku pamięci wektorowej. Przekazywany jest wskaźnik, a nie 'unique_ptr'. Oczywiście, wskaźnik jest zniszczony, ale czy mam gwarancję, że destruktor 'unique_ptr' działa i usuwa wskaźnik? –

+0

Faktycznie fakt, że 'emplace' jest operacją" no-op "dla wyjątku, mówi raczej o' int' nie otrzymującym 'delete'd poprawnie, ponieważ jego alokacja odbywa się całkowicie poza 'emplace', podczas gdy konstrukcja (deallocating)) inteligentny wskaźnik dzieje się w środku. –

+1

Erm, od kiedy trzeba tu przypisać "błąd"? Jeśli chodzi o "całkowicie bezpieczne" sposoby, aby to zrobić, z pewnością istnieją "bezpieczne" sposoby na zrobienie tego. Ale jeśli wymusisz użycie konstruktora ruchu, możesz równie dobrze użyć 'push_back', ponieważ wymusza ono prawidłowe zachowanie we wszystkich przypadkach. –