Zawsze zapomnisz posprzątać, lepiej niech kompilator sprzątnie za Ciebie
Popatrzmy na taki kawałek kodu (znaleziony przeze mnie w weryfikowanym rzeczywistym ważnym programie):
Message * msg = new Message();
// ... trochę różnorakich przygotowań
// Funkcja z pewnej zewnętrznej biblioteki, upycha pobrane dane do msg i zwraca status
int result = receive_message(flags, msg);
// Funkcja badająca status i rzucająca wyjątek w razie gdy wykryto błąd
VerifyResult(result);
// Funkcja która przetwarza komunikat a na koniec zwalnia zaalokowaną dlań pamięć
Process(msg);
Jak nietrudno po chwili zastanowienia zauważyć, po każdym błędzie (a błędy były rejestrowane, po czym program kontynuował działanie) mieliśmy wyciek pamięci. Po wskazaniu mu błędu, autor chciał z miejsca go poprawić zastępując verifyResult rozwiniętym if-em zawierającym polecenie delete. Można i tak - ale nie jest to mądre (wcześniej czy później w tym kodzie pojawi się możliwość zgłoszenia innego wyjątku, jakiś warunkowy return a może break).
Znacznie mądrzejszym rozwiązaniem (zakładając, że msg musi być alokowane dynamicznie) jest wykorzystanie jakiegokolwiek wariantu sprytnego wskaźnika, np. tak:
auto_ptr<Message> msg(new Message());
// Dalej tak, jak było
W razie przerwania przez wyjątek naturalnej sekwencji wykonania, pamięć zostanie zwolniona w momencie zwijania stosu bieżącej funkcji. Podobnie obsłużymy return czy break czy jakiekolwiek inne zgodne z zasadami języka zakończenie bloku.
Z każdym kolejnym projektem w C++ umacniam się w przekonaniu, że dobrze napisany program nie powinien zawierać żadnej instrukcji delete! Z wyjątkiem klasy implementującej sprytne wskaźniki (standardowy auto_ptr jest trochę niemądry, lepiej używać jakiegoś 'pełnego' sprytnego wskaźnika z licznikiem referencji). Pojawiający się tu narzut może mieć znaczenie w grach 3D ale w aplikacjach biznesowych nie ma szans zostać zauważony.
- «Horror nazewniczy pod Windows
- Co ma wspólnego Oracle z numeric_limits»
- ↑C++ - sztuczki i niebezpieczeństwa