1.1 初步跟踪的实现
我们想要让trace 对象记录一些事件消息,比如进入某个函数,离开某个函数,以及其他介入这两者之间的某些重要消息。如下:
C++ Code
1
2 3 4 5 6 7 8 |
int myFunction(
int x)
{ string name = "myFunction"; Trace t(name); ... string moreInfo = "more interesting info"; t.debug(moreInfo); } |
我们下面的Trace类来实现这一功能。
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
class Trace
{ public: Trace( const string &name); ~Trace(); void debug( const string &name); static bool traceIsActive; private: string theFunctionName; }; inline Trace::Trace( const string &name): theFunctionName(name) { if(traceIsActive) { cout << "Enter function" << name << endl; } } inline void Trace::debug( const string &msg) { if(traceIsActive) { cout << msg << endl; } } inline Trace::~Trace() { if(traceIsActive) { cout << "Exit function" << theFunctionName << endl; } } |
1、I/O的开销是高昂的。
2、函数调用的开销是要考虑的一个因素,因此我们应该讲短小、频繁调用的函数内联。
3、复制对象的开销是高昂的,最好选择引用,而不是传值。
我们的做法是尽量少定义string类型。减少对象的定义和销毁的代价。利用const char *代替string来实现,下面的是完整代码。
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
#include<iostream>
#include<string> #include<windows.h> using namespace std; /* class Trace { public: Trace(const string &name); ~Trace(); void debug(const string &name); static bool traceIsActive; private: string theFunctionName; }; inline Trace::Trace(const string &name):theFunctionName(name) { if(traceIsActive) { cout<<"Enter function"<<name<<endl; } } inline void Trace::debug(const string &msg) { if(traceIsActive) { cout <<msg<<endl; } } inline Trace::~Trace() { if(traceIsActive) { cout<<"Exit function"<<theFunctionName<<endl; } }*/ //改进版 class Trace { public: Trace( const char *name); ~Trace(); void debug( const string &name); static bool traceIsActive; private: string *theFunctionName; }; inline Trace::Trace( const char *name):theFunctionName( 0) { if(traceIsActive) { cout<< "Enter function"<<name<<endl; theFunctionName= new string(name); } } inline void Trace::debug( const string &msg) { if(traceIsActive) { cout <<msg<<endl; } } inline Trace::~Trace() { if(traceIsActive) { cout<< "Exit function"<<*theFunctionName<<endl; delete theFunctionName; } } bool Trace::traceIsActive= true; int addOne( int x) { char *name= "addOne"; Trace t(name); return x+ 1; } int main() { SYSTEMTIME t1,t2; int j= 10000000; int y= 0; Trace::traceIsActive= false; GetSystemTime(&t1); for( int i= 0;i<j;i++) { y=addOne(i); } GetSystemTime(&t2); cout<<t2.wMilliseconds-t1.wMilliseconds<<endl; system( "pause"); } |
1.2 要点
1、对象定义触发隐形地执行构造函数和析构函数。我们称其为“隐形执行”而不是“隐形开销”,是因为对象的构造和销毁并不总是意味着产生开销。内联函数使用减少函数调用的开销。
2、通过引用传递对象还是不能保证良好的性能,所以避免对象的复制的确有利于提高性能。
3、不要把精力浪费在计算结果根本不会被使用的地方。
4、在完成同样的简单工作,char指针有时比string对象更加有效。
5、内联消除了常被使用的小函数调用所产生的函数开销。