分享
 
 
 

永恒与瞬间之美(C++技术小品文)

王朝c/c++·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

关键字:C++、静态对象、临时对象

本文将以一个简单的例子逐步地讲解静态对象和临时对象在C++程序设计中的使用技巧。

故事的开始

一天,我在写一个有复杂内存结构的MFC程序,为了看到我关心的内存数据结构内容,我要频繁地将大量的数据TRACE到屏幕上来。当我这么做时,天哪,我的CPU占用率达到了100%!在悲叹VC.NET的效率和我的老爷机的同时,我请出了我的珍藏法宝“DBWIN”,可是没想到,效率并没有太多提高,还使我的老爷机上所有运行着的DEBUG版程序把信息全都打印在“DBWIN”的窗口上,于是,我痛下决心,自己写一个TRACE。我的想法很简单,申请一个Console,将信息写上去。

第一版:丑小鸭的诞生

我用最简单的技术,大体上需要在程序运行开始时加入一个Console,在结束时自动释放掉。所以我利用了一下C++对象特性。写了一个类:

class MyConsole

{

public:

MyConsole()

{

m_bHaveConsole=AllocConsole();

}

~MyConsole()

{

if(m_bHaveConsole)

FreeConsole();

}

BOOL m_bHaveConsole;

};

有了它之后,只要定义一个全局类对象,就拥有了程序开始得到控制台,结束自动释放的好处。然后添加了如下的代码:

#include <conio.h>

#undef TRACE

#define TRACE _cprintf

在XApp.cpp定义全局的theApp前写上:

MyConsole theConsole;//这样我们拥有了一个全局可用的控制台!!!

XApp theApp;

好了,编译、运行,现在,所有的TRACE都打印在Console上了。

可是,第一只丑小鸭有很大缺点,首先,每次使用之前打扰了用户的代码,我们都想写用户仅需#include头文件就能运行的代码,而这里必须在CPP文件中加入MyConsole theConsole,这让我心如油煎。可是,该对象实体不能加在.H文件中。我开始想到的是静态类成员,可是这样的.H不能包含在两个以上的.CPP中,否则链接会有错误。于是,我想到了静态类对象。

第二版:成为天鹅前的涅槃

我把我的MyTrace.H改为如下内容

#ifndef MYTRACE_HPP

#define MYTRACE_HPP

#include <conio.h>

class MyConsole

{

public:

MyConsole()

{

m_bHaveConsole=AllocConsole();

}

~MyConsole()

{

if(m_bHaveConsole)

FreeConsole();

}

BOOL m_bHaveConsole;

};

class MyTraceCondition

{

public:

static Fun()

{

static MyConsole theConsole;

}

};

#undef TRACE

#define TRACE MyTraceCondition::Fun();_cprintf

#endif

这里我第一次用到了静态类对象,注意它与全局静态对象(包括静态类成员其实也是全局静态的一种变形)的区别。静态类对象在第一次使用时被构造,在以后的反复使用中并不被重新创建,也就是说,你可以这样来验证:

MyConsole()

{

m_bHaveConsole=AllocConsole();

_cprintf(“alloc\n”);

}

~MyConsole()

{

if(m_bHaveConsole)

{

_cprintf(“free\n”);

FreeConsole();

}

你会发现仅在第一次调用TRACE时,会输出“alloc”。有了静态对象的使用,我们可以把一个对象实体隐藏在.H文件中,不需要打扰用户的代码了。而且该方法还是高效的,效率和全局对象一样高。但是,当我的工程中运行两个以上线程都要用到TRACE时,我又有了新问题。你看到了,这种调用TRACE的方式并非线程安全,至少会使打印出来的信息杂乱地混在一起。你也许想到了使用线程安全地CRT版本,千万别那样做,多线程的代码大部分是不需要互斥的,如果为了一点代码的安全而导致整体代码效率降低,不值得。

于是我开始了在.H文件中添加临界区。要求所有的线程在调用TRACE中的_cprintf时进入相同的临界区。于是我必须对_cprintf进行点儿包装。我不能使用全局临界区,因为这样会导致我不得不搞出一个.CPP文件,同样我也不能使用使用静态类成员。那么使用普通的类成员做临界区吗?NO!,这样每次调用的就不是一个临界区了。于是,也许你猜到了。

——我第二次使用了静态对象!

#include <atlcore.h>

class MyTrace

{

public:

MyTrace():pTraceFun(_cprintf)

{

static CComAutoCriticalSection TheCriticalSection;

pCriticalSection=&TheCriticalSection;

pCriticalSection->Lock();

}

~MyTrace()

{

pCriticalSection->Unlock();

}

int(*pTraceFun)(const char*,...);

private:

CComAutoCriticalSection * pCriticalSection;

};

现在,不论你怎么使用,都会进入相同的临界区。

好吧,现在#define TRACE…,噢,gold!我犯了极大的错误,我简直没法写出对TRACE的重定义。怎么利用MyTrace呢?难道写成

#define TRACE MyTraceCondition::Fun();

MyTrace tracetmp;

(*tracetmp. pTraceFun)

不,我无法知道用户将怎样使用TRACE。也许他们更愿意在一对{}中使用N次,那这段代码无疑成了毒瘤。

于是,灵光一闪,我发现了成为天鹅的关键

第三版:成为漂亮的天鹅

哈哈,我将头文件内容改为这样

#ifndef MYTRACE_HPP

#define MYTRACE_HPP

#include <conio.h>

#include <atlcore.h>

class MyTrace

{

public:

MyTrace():pTraceFun(_cprintf)

{

static CComAutoCriticalSection TheCriticalSection;

pCriticalSection=&TheCriticalSection;

pCriticalSection->Lock();

}

~MyTrace()

{

pCriticalSection->Unlock();

}

int(*pTraceFun)(const char*,...);

private:

CComAutoCriticalSection * pCriticalSection;

};

class MyConsole

{

public:

MyConsole()

{

m_bHaveConsole=AllocConsole();

}

~MyConsole()

{

if(m_bHaveConsole)

FreeConsole();

}

BOOL m_bHaveConsole;

};

class MyTraceCondition

{

public:

static MyTrace Fun()

{

static MyConsole theConsole;

return MyTrace();

}

};

#undef TRACE

#define TRACE (*MyTraceCondition::Fun().pTraceFun)

#endif

哈哈,你看到了,我运用了临时对象的特性,临时对象在失去外部的引用环境时(在本例中即在TRACE执行完时)自动析构,这样以上就为我们自动生成了一个临界区。并且没有显式的对象产生。在MyTrace的构造和析构函数中打印点儿东西,你同样可以看到临时对象的构造和析构过程。

总结经验

临时对象往往是要谨慎对付的家伙,静态对象也不是所有的人都清楚的,但作为C++的FUN,总是需要创造性的思维来利用语言的强大特性,对语言的一些容易出错的细节合理利用往往可以使程序妙笔生花。希望看了这篇文章,对你有所帮助,C++万岁。

我歌月徘徊

我舞影凌乱

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有