Posts tagged ‘stack’

Stos wywołań funkcji

2008-06-13 13:42

Jedną z bardziej przydatnych informacji podczas znajdowania przyczyn błędów wykonania jest śledzenie stosu (stack trace; właściwie to nie ma dobrego polskiego tłumaczenia, jak zwykle zresztą :]). Dzięki niemu możemy mieć informacje o kolejnych wywołaniach funkcji, które doprowadziły błędu wykonania. Zwykle stack trace jest dostępny z poziomu złapanego obiektu wyjątku – np. poprzez właściwość System.Exception.StackTrace w .NET czy metody java.lang.Throwable.get/printStackTrace w Javie.

Standardowa klasa exception w C++ nie posiada podobnej funkcjonalności, bo w tym języku stos nie jest automatycznie śledzony. Przy pewnym wysiłku możemy aczkolwiek zapewnić sobie podobną funkcjonalność – chociażby tak:

  1. typedef std::list<std::string> StackTrace;
  2.  
  3. class Trace
  4. {
  5.     private:
  6.         static StackTrace ms_Trace;
  7.  
  8.     public:
  9.         Trace(const std::string& item) { ms_Trace.push_back (item); }
  10.         ~Trace()    { ms_Trace.pop_back(); }
  11.  
  12.     friend const StackTrace& GetStackTrace()    { return ms_Trace; }
  13. };
  14. StackTrace Trace::ms_Trace;    // inicjalizacja pola statycznego (w .cpp)
  15.  
  16. // makro (dla Visual C++)
  17. #define GUARD Trace __trace(__FUNCTION__ " [" __FILE__ ", line " __LINE__ "]")

Przechowujemy po prostu globalną listę z danymi wszystkich wywoływanych funkcji. Elementy do niej dodawane są przy wejściu w każdą funkcję, która na początku ma makro GUARD:

  1. int Foo() { GUARD; /* ... */ }

zaś zdejmowane wtedy, gdy pomocniczy obiekt typu Trace wyjdzie poza swój lokalny zasięg – czyli po opuszczeniu funkcji. To sprawia, że na liście mamy zawsze informacje o wszystkich wywołaniach funkcji prowadzących do aktualnego miejsca (jakie one są, zależy od kompilatora; użyte wyżej makro __FUNCTION__ nie jest na przykład standardową częścią C++). Tworząc obiekt wyjątku, możemy więc zapisać kopię tej listy, by można ją było odczytać w bloku catch i wyświetlić.
Rozwiązanie nie jest oczywiście bardzo ładne, bo wymaga dodatkowej linijki w każdej funkcji. Zdaje się jednak, że nie ma żadnego sposobu, by tę niedogodność wyeliminować. Ja przynajmniej takiego nie znam :)

Tags: , , ,
Author: Xion, posted under Programming » 11 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.