2015-12-14 19 views
6

Jest to ćwiczenie z C++ Primer, rozdział 18:sposobów, aby uniknąć wycieku pamięci, gdy wyjątek rzucone

void exercise(int *b, int *e) 
{ 
    vector<int> v(b, e); 
    int *p = new int[v.size()]; 
    ifstream in("ints"); 
    // exception occurs here 
} 

Powyższy kod mogłoby spowodować wyciek pamięci, ponieważ pamięć uda nam bezpośrednio (tj p) nie jest automatycznie zwolniony, gdy wystąpi wyjątek.

Ćwiczenie 18.3:

Istnieją dwa sposoby, aby prawidłowo poprzednią pracę kodu, jeśli jest wyjątek. Opisz je i zastosuj.

Wiem, że możemy użyć inteligentnego wskaźnika, aby uniknąć tej pułapki:

void exercise(int *b, int *e) 
{ 
    vector<int> v(b, e); 
    unique_ptr<int[]> p(new int[v.size()]); 
    ifstream in("ints"); 
    // exception occurs here 
} 

czyli

void exercise(int *b, int *e) 
{ 
    vector<int> v(b, e); 
    shared_ptr<int> p(new int[v.size()], [](int *p){ delete[] p; }); 
    ifstream in("ints"); 
    // exception occurs here 
} 

Nie jestem pewien, czy to są TWO sposoby. W końcu są one praktycznie takie same. Więc pomyślałem o inny sposób:

void exercise(int *b, int *e) 
{ 
    vector<int> v(b, e); 
    int *p = new int[v.size()]; 
    ifstream in("ints"); 
    // exception occurs here 
    if(!in) 
     throw p; 
} 

// caller 
try { 
    exercise(b, e); 
} catch (int *err) { 
    delete[] err; // initialize err with b and delete e. 
} 

Jeśli wystąpi wyjątek, rzucać p zainicjować innego wskaźnika, a także usunąć ten jeden. Wiem, że to nie jest doskonałe rozwiązanie, ponieważ mogą wystąpić inne wyjątki, więc nie mam nawet szansy na wyrzucenie p. Ale nie mogę wymyślić lepszego. Czy możesz pomóc znaleźć drugą drogę?

+1

Co powiesz na prosty try-catch dla wszystkiego ('...') w ramach funkcji? Usuń i przeprowadź tam ponownie. ... A może użyć wektora dla 'p'? – deviantfan

+0

O tak, 'rethrow' jest znacznie lepszy dla tego problemu. Dziękuję Ci! – chihyang

+1

Zapominasz 'wektora p (v.size());' –

Odpowiedz

4

Można jawnie złapać i ponownie rzucić wyjątek:

void exercise(int *b, int *e) 
{ 
    vector<int> v(b, e); 
    int *p = new int[v.size()]; 
    try { 
     ifstream in("ints"); 
     // exception occurs here 
    } catch (...) { 
     delete[] p; 
     throw; 
    } 
    delete[] p; 
} 

Oczywiście to nie działa tak dobrze, jeśli masz wiele zasobów za darmo, bo może skończyć się z zagnieżdżonych bloków try/catch . Nie wspominając, że masz dwa delete s dla jednego new. A więc preferowane jest RAII.