1. 程式人生 > >C++中-如何跟蹤函式和類

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章