2011-10-10 15 views
5

Poniższy przykład powoduje, że możliwy jest wyciek pamięci, ponieważ destruktor nie działa dla obiektu, na którym jest obsługiwany wyjątek podczas uruchamiania jego konstruktora. gdzie poradzę sobie z tym wyciekiem pamięci?Wyłapywanie wyjątków w konstruktorze

#include <exception> 

class MyClass { 

public: 
     MyClass() 
     { 
      c = new char[5]; 
      throw std::runtime_error("test"); 
     } 

     ~MyClass() 
     { 
      delete[] c; 
     } 

private: 
    char *c; 
}; 

int main() 
{ 
    try 
    { 
     MyClass Obj; 

    } 
    catch (std::runtime_error) 
    { 

    } 
} 

Odpowiedz

5

Jesteś lepiej wyłączyć za pomocą RAII, inteligentny wskaźnik w tym przypadku ma charakter szczególny.

Lub alternatywnie można użyć strategii Two Phased Construction.

Zawsze możesz użyć załączając try-catch bloki wewnątrz ciała konstruktora i jawnie wywołać usunięcie wszystkich tych zasobów, które dynamicznie alokowanych ale myśleć o sytuacji, w której trzeba n ilość zasobów są dynamicznie przydzielane, staje się naprawdę brudny jawnie śledzić z każdego zasobu, który musisz zwolnić w catch, w takim scenariuszu, RAII zapewnia najlepsze rozwiązanie, ponieważ wtedy każdy zasób pośrednio zajmuje się własną alokacją i nie musisz mieć kosztów utrzymania każdego zasobu.

boost::scoped_ptr lub są przystosowane do tego scenariusza zamiast jakichkolwiek surowych wskazówek.

+2

Co wzywa do tego przegłosowania? RAII to najlepszy sposób, aby to osiągnąć, a jeśli ktoś mówi inaczej, to jest niepoprawny. Jeśli czujesz się odpowiedzialny za Downvote, poczuj się na tyle odpowiedzialny, aby wyjaśnić nam, dlaczego? A jeśli nie możesz i po prostu * czujesz * to jest złe, to nie jesteś wystarczająco wykwalifikowany, aby zrobić sobie krzywdę, niech ktoś inny to zrobi. –

+0

jest to rozwiązanie oparte na materiałach związanych z C++ 11? – user103214

+0

Nie, to jest C++ 03. –

6

Złap wyjątek w konstruktorze, uporządkuj (zwolnij pamięć), a następnie wyrzuć wyjątek bez wycieku pamięci.

+0

Destruktor nigdy nie był wywoływany, gdy ponownie zgłaszam wyjątek bez wycieku pamięci w konstruktorze. czy jest jakikolwiek powód? – user103214

+1

@ user974191: Konstrukcja obiektu nie jest kompletna aż do zakończenia klocka konstruktora. Destruktor jest wywoływany tylko dla obiektu, który jest kompletny. Jeśli konstruktor nie został wykonany, obiekt nie istnieje, a zatem nie zostanie wywołany żaden destruktor. –

1

można złapać wyjątek w ciele konstruktora, co zrobić porządki trzeba, a następnie przekaż wyjątek z throw;

powiedział, wyjątków i ręcznego przemieszczania pamięci nie chodzą ładnie razem. Znacznie lepiej będzie użyć obiektu, który automatycznie zarządza pamięcią dla elementu c (np. std::string, std::vector<char>, std::unique_ptr<char[]> itd.). Naprawdę potrzebujesz tylko zarządzać pamięcią jawnie, jeśli piszesz klasę podobną do tej, której celem jest dbanie o tę pamięć.

4

Jednym ze sposobów jest throw warunkowy wyjątek na początku konstruktora, a następnie przydzielenie pamięci.

MyClass() 
    { 
    if(<condition>) 
     throw std::runtime_error("test"); 
    c = new char[<SIZE>]; 
    } 

Innym sposobem jest użycie specjalnej składni try-catch() załączając konstruktora:

MyClass() 
    try { 
    c = new char[5]; 
    throw std::runtime_error("test");; 
    } 
    catch(std::runtime_error e) { 
    delete[] c; 
    } 

Demo.