C++中-如何跟蹤函式和類
下面是程式的輸出:
用這種方法我們可以通過log可以很清楚的看到程式執行到函式foo了,也就是通過程式的輸出“hello”和“Goodbye”知道程式執行到foo這個函數了。換句話說我們通過
在函式中插入了一個Trace類物件來知道該函式什麼時候被呼叫的。
但是我們的程式肯定不止一個函式,如果我們需要對多個函式進行跟蹤,這種方法就不太適用了,因為無論在哪個函式里程序都輸出“hello"和"Goodbye”,
我們並不知道這些資訊是哪個函式輸出的。
為了解決這個問題,下面對Trace類進行了改進
#include <iostream>
using namespace std;
class Trace
{
public:
Trace(const string start, const string s):end(s)
{
cout<<start<<endl;
}
~Trace()
{
cout<<end<<endl;
}
private:
string end;
};
void foo()
{
Trace t("Begin foo()", "End foo()");
cout<<"Do something in function foo()."<<endl;
}
int main()
{
foo();
return 0;
}
下面是程式的輸出:
這個Trace類做了一些改進,更加智慧一些,通過向建構函式傳遞了兩個引數,一個引數在Trace物件構造時打印出來,另一個在Trace物件析構時打印出來,
這樣我們就可以向建構函式傳遞與函式名相關的引數資訊了。這個Trace類應該很接近於實用了,可是當我們使用的過程中會發現這個類會存在幾個問題:
1. 列印的資訊有很多共同點,不利於我們檢視,比如都以Begin開始,End結束等,有人也許不明白,列印的資訊由我們傳遞給Trace建構函式的引數來決定,但是試想以下
我們有很多個函式,我們不太可能在每個函式中給Trace物件傳遞差異很大的字串,這就像C++為什麼要引入namespace來解決命名衝突的問題。
2. 眾所周知,程式分為Release版和Debug版本,在Release版本中我們不希望打印出這些除錯資訊,而在這種情況下我們要靜止列印這些除錯資訊會很困難。
3. 我們都是在Trace類的建構函式中用cout輸出資訊,如果我們不想在標準輸出列印這些資訊,這種情況下沒有辦法重定向到其他的檔案
再來看看下面的程式碼:
#include <iostream>
#include <ostream>
#include <fstream>
using namespace std;
class Channel
{
public:
Channel(ostream* output = &cout):trace_file(output)
{
}
void reset(ostream* output)
{
trace_file = output;
}
private:
friend class Trace;
ostream* trace_file;
};
class Trace
{
public:
Trace(const string s, Channel* cn):name(s), cp(cn)
{
if(cp->trace_file)
*(cp->trace_file)<<"Begin "<<name<<endl;
}
~Trace()
{
if(cp->trace_file)
*(cp->trace_file)<<"End "<<name<<endl;
}
private:
Channel* cp;
string name;
};
Channel subsystem1(&cout);
Channel subsystem2(0);
void foo1()
{
Trace t1("foo1()", &subsystem1);
cout<<"Do something in function foo1()."<<endl;
}
void foo2()
{
Trace t2("foo2()", &subsystem2);
cout<<"Do something in function foo2()"<<endl;
}
int main()
{
foo1();
foo2();
return 0;
}
在foo1()函式中我們指定了將除錯資訊列印在標準輸出cout上,而在foo2()函式中我們將輸出重定向到NULL,這點不難理解,在Linux下我們經常將命令輸出的不需要的資訊重定向到/dev/null這個檔案中,
這個檔案就像是個黑洞,進去的資料沒有出來的。這裡的原理是一樣的,很顯然我們可以隨意選擇除錯資訊所輸出的檔案,或者是不輸出。
在我們程式碼除錯的過程中,我認為這種技術技術比較有用的
參考文獻:
1.《Ruminations on C++》第27章