Potrzebowałem w prosty sposób i łatwy sposób logować moment tworzenia i niszczenia obiektów. W najprostszym wypadku wystarczyłoby przeciążyć operator new i delete, ale wtedy logowanie dotyczyłoby tylko obiektów tworzonych na stercie. A ja chce i stos, i stertę ;)
No to wystarczy w konstruktorze i destruktorze umieścić wywołanie funkcji logującej i problem znika.
Tylko, że w każdej klasie musimy dodać ten kod, a jak wspomniałem sposób powinien być najprostszy i najłatwiejszy.
W takim razie szablonowa klasa podstawowa z logowaniem w konstruktorze i destruktorze?
Tak, to będzie dobry pomysł, ale co tak naprawdę zyskujemy w porównaniu do wrzucania kodu w każdą klasę? Skoro tutaj też musimy zadbać, aby nasza klasa dziedziczyła po tej klasie z logowaniem.
Zyskamy jedynie możliwość szybkiej zmiany i rozbudowy funkcji logującej, bo wystarczy wtedy tylko zmienić w jednym miejscu, a nie szlajać się po całym kodzie projektu.
Głównym celem naszego object tracingu jest wypisywanie w logu informacji jaki obiekt został stworzony i zniszczony, dlatego musimy znać nazwę danej klasy pochodnej.
Możemy pokombinować coś z Quoted Literals as Template Arguments, ale nie bardzo to nadaje się do naszego przypadku, przynajmniej mi nie udało się z tym nic zrobić ;) Zatem możemy skorzystać z makr lub RTTI. Wszakże trading potrzebny jest nam w wersji debug, zatem w wersji finalnej nie będzie żadnych dodatkowych kosztów w czasie działania.
Nasza szablonowa klasa bazowa mogłaby wyglądać tak:
template<typename T> class ObjectTracing { public: ObjectTracing() { ::LogTrace("%s created", typeid(T).name()); } ~ObjectTracing() { ::LogTrace("%s destroyed", typeid(T).name()); } }; |
A jej użycie bardzo proste:
class MyClass : public ObjectTracing<MyClass> { // ... }; |
Oczywiście znakowa reprezentacja nazwy pobrana metodą name() obiektu type_info zależy od implementacji, dlatego może zostać wzbogacona o jakieś dodatkowe prefiksy lub sufiksy.
W moim programie korzystam z wxWidgets, dlatego swój kod oparłem o RTTI (a raczej jej namiastce) tejże biblioteki, które w wolnym tłumaczeniu polega na umieszczaniu za pomocą makr statycznych pól w klasie z informacjami o jej typie i właściwościach.
W sumie mechanizm object tracingu potrzebny mi jest tylko w wersji debug, także zadbam o to, aby w moich klasach nie dziedziczących po wxowych, w wersji release pola z danymi RTTI się nie pojawiły. Bo i tak tylko jest mi ono potrzebne do tracingu.
Nic nowego nie wymyśliłem ;)