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