2014-09-24 14 views
14

An MSDN page about smart pointers zawiera promowane ostrzeżenie o tworzeniu inteligentnych wskaźników w listach parametrów:Inteligentne wskaźniki i zasady alokacji lista parametrów

Zawsze tworzyć inteligentne kursory na osobnej linii kodu, nigdy w liście parametrów, tak że subtelna wyciek zasobów nie nastąpi z powodu pewnych reguł alokacji listy parametrów.

Jakie są zasady alokacji listy parametrów, do których się odnoszą? W jakich okolicznościach może nastąpić wyciek zasobów?

Odpowiedz

8

Odnosi się do możliwości oceny parametrów w innej kolejności, np.

func(unique_ptr<MyClass>(new MyClass), a(), b()); 

jeśli kolejność oceny jest: a(), MyClass(), b(), następnie unique_ptr jest skonstruowany, że może się zdarzyć, że b() rzuty i pamięć będzie przeciekał.

Zabezpieczenie (dodane w C++ 14, a także bardziej wydajne) to użycie make_unique (przy założeniu, że MSVC i zgodnie z wersją kompilatora, może być konieczne zdefiniowanie go samodzielnie lub take a look here). To samo dotyczy shared_ptr.

Spójrz at the notes for std::make_shared here też:

Ponadto, kod taki jak f(std::shared_ptr<int>(new int(42)), g()) może spowodować przeciek pamięci, jeśli g zgłasza wyjątek, ponieważ g() można nazwać po new int(42) i przed konstruktora shared_ptr<int>. Ten nie występuje w f(std::make_shared<int>(42), g()), ponieważ dwie wywołania funkcji nigdy nie są przeplatane.

+1

Ponieważ OP wygląda na to, że używasz VS, myślę, że 'make_unique' jest już obsługiwane w VS2013. – dyp

+0

Dzięki, edytowane dla jasności. VS2012 może być problem, ponieważ nie obsługuje szablonów variadic, pod warunkiem, że link rezerwowy z problemem. (lub OP może wypróbować CTP, uważam, że aktualizacja 2 powinna działać). –

+1

W każdym razie istnieją dodatkowe powody, by preferować 'allocate_shared' i' make_shared', aby to zrobić ręcznie: Efektywność. – Deduplicator

1

Jeśli to zrobić:

func(shared_ptr<Foo>(new Foo), shared_ptr<Bar>(new Bar)); 

I podpis jest:

void func(shared_ptr<Foo>, shared_ptr<Bar>); 

Co się stanie, jeśli jeden z konstruktorów rzuca? Może się zdarzyć, że został wywołany raz, a następnie drugi się nie powiedzie (nie wiesz, który z nich zostanie wywołany jako pierwszy). Jeśli tak się stanie, jeden z obiektów może zostać ujawniony, ponieważ nigdy nie był przechowywany przez menedżera zasobów.

można przeczytać więcej tutaj: http://www.gotw.ca/gotw/056.htm

+0

@PiotrS .: thanks , zaktualizowane, aby to odzwierciedlić. –

0

Problemem jest to, że jeśli masz funkcję, która trwa kilka argumentów:

void func(const std::shared_ptr<MyFirstClass>& ptr, const MySecondClass& ref); 

i wywołać tę funkcję tak:

func(std::shared_ptr<MyFirstClass>(new MyFirstClass), MySecondClass()); 

kompilator może dowolnie wykonywać wyrażenia na liście argumentów w dowolnej kolejności. Niektóre z tych zamówień mogą być problematyczne.Na przykład, wyobraźmy sobie, że kompilator zdecyduje się wykonać

new MyFirstClass 

a następnie

MySecondClass() 

i wreszcie c'tor std :: shared_ptr < MyFirstClass> (przekazując jej adres instancji MyFirstClass który został przydzielony w wolnym sklepie w pierwszym kroku).

Jak dotąd tak dobrze. Ale jeśli drugi krok zgłasza wyjątek, to shared_ptr nigdy się nie skonstruuje, a twój darmowy sklep przydzielony do MyFirstClass-instancja jest na zawsze stracony.

Powiązane problemy