📄 gdi+编程中的一条错误信息及其原因分析.htm
字号:
color=#000099><BR>#ifdef _DEBUG<BR>#define new DEBUG_NEW<BR>#undef THIS_FILE<BR></FONT><FONT
color=#990000>static</FONT><FONT
color=#ff6633> char</FONT> THIS_FILE<B><FONT
color=#663300>[] =</FONT></B> __FILE__<B><FONT
color=#663300>;</FONT></B><FONT
color=#000099><BR>#endif<BR></FONT>这几行从来都不会引起我们注意的代码有什么问题呢<B><FONT
color=#663300>?</FONT></B>为什么会使得我们的代码报告如上所述的编译错误呢<B><FONT
color=#663300>?</FONT></B><BR>让我们来看看DEBUG_NEW的定义(在afx<B><FONT
color=#663300>.</FONT></B>h中):<FONT
color=#000099><BR>#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)<BR></FONT><I><FONT
color=#999999><BR>// Memory tracking allocation<BR></FONT></I><FONT
color=#ff6633>void</FONT><B><FONT
color=#663300>*</FONT></B> AFX_CDECL<FONT
color=#990000> operator new</FONT><B><FONT
color=#663300>(</FONT></B>size_t nSize<B><FONT
color=#663300>,</FONT></B> LPCSTR lpszFileName<B><FONT
color=#663300>,</FONT></B><FONT
color=#ff6633> int</FONT> nLine<B><FONT
color=#663300>);</FONT></B><FONT
color=#000099><BR>#define DEBUG_NEW new(THIS_FILE, __LINE__)<BR>#if _MSC_VER >= 1200<BR></FONT><FONT
color=#ff6633>void</FONT> AFX_CDECL<FONT
color=#990000> operator delete</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#ff6633>void</FONT><B><FONT
color=#663300>*</FONT></B> p<B><FONT
color=#663300>,</FONT></B> LPCSTR lpszFileName<B><FONT
color=#663300>,</FONT></B><FONT
color=#ff6633> int</FONT> nLine<B><FONT
color=#663300>);</FONT></B><FONT
color=#000099><BR>#endif<BR></FONT>看到这里你可能会想,<FONT
color=#990000>new</FONT>被define成了DEBUG_NEW,而后者又被define成了<FONT
color=#990000>new</FONT><B><FONT
color=#663300>(...)</FONT></B>,这不是成了个循环<B><FONT
color=#663300>?</FONT></B>非也。由于afx<B><FONT
color=#663300>.</FONT></B>h早于任何其它头文件被包含<B><FONT
color=#663300>(</FONT></B>stdafx<B><FONT
color=#663300>.</FONT></B>h包含afxwin<B><FONT
color=#663300>.</FONT></B>h,afxwin<B><FONT
color=#663300>.</FONT></B>h又包含了afx<B><FONT
color=#663300>.</FONT></B>h,而MFC要求我们在任何有效代码之前包含stdafx<B><FONT
color=#663300>.</FONT></B>h,当然,这不是必须的<B><FONT
color=#663300>)</FONT></B>,所以DEBUG_NEW的定义早于后面的#define<FONT
color=#990000> new</FONT> DEBUG_NEW,也就是说这个define只对后面的代码有效,对前面已经include了的afx<B><FONT
color=#663300>.</FONT></B>h中的代码是无效的。<BR><BR>上面只是题外话,现在回到正题。<BR>MFC重载<FONT
color=#990000>operator new</FONT>,是为了方便定位内存泄漏,重载后的<FONT
color=#990000>operator new</FONT>会记录下所分配的每块内存对应的__FILE__和__LINE__信息。一般来讲,标准的<FONT
color=#990000>operator new</FONT>的声明如下:<FONT
color=#ff6633><BR>void</FONT><B><FONT
color=#663300> *</FONT></B>__cdecl<FONT
color=#990000> operator new</FONT><B><FONT
color=#663300>(</FONT></B>size_t<B><FONT
color=#663300>);</FONT></B><BR>即它只有一个参数,只接收一个size信息。我们的如下代码<FONT
color=#ff6633><BR>int</FONT><B><FONT
color=#663300>*</FONT></B> pi<B><FONT
color=#663300> =</FONT></B><FONT
color=#990000> new</FONT><FONT
color=#ff6633> int</FONT><B><FONT
color=#663300>;</FONT></B><I><FONT
color=#999999> // the same as int* pi = new int(); or int* pi = new int[1];<BR></FONT></I>等价于<FONT
color=#ff6633><BR>int</FONT><B><FONT
color=#663300>*</FONT></B> tpi<B><FONT
color=#663300> = (</FONT></B><FONT
color=#ff6633>int</FONT><B><FONT color=#663300>*)</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#990000>sizeof</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#ff6633>int</FONT><B><FONT
color=#663300>));</FONT></B><I><FONT
color=#999999> // attention: this line cannot pass compilation if you have define DEBUG_NEW<BR></FONT></I><FONT
color=#ff6633>int</FONT><B><FONT
color=#663300>*</FONT></B> pi<B><FONT
color=#663300> =</FONT></B> tpi<B><FONT
color=#663300>;</FONT></B><BR>同理,定义DEBUG_NEW前,文章开头报错的这条语句:<BR>Bitmap<B><FONT
color=#663300>*</FONT></B> bmPhoto<B><FONT
color=#663300> =</FONT></B><FONT
color=#990000> new</FONT> Bitmap<B><FONT
color=#663300>(</FONT></B> THUMBNAIL_WIDTH<B><FONT
color=#663300>,</FONT></B> THUMBNAIL_HEIGHT<B><FONT
color=#663300>,</FONT></B> PixelFormat24bppRGB<B><FONT
color=#663300> );</FONT></B><BR>等价于<BR>Bitmap<B><FONT
color=#663300>*</FONT></B> tbmPhoto<B><FONT
color=#663300> = (</FONT></B>Bitmap<B><FONT
color=#663300>*)</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#990000>sizeof</FONT><B><FONT
color=#663300>(</FONT></B>Bitmap<B><FONT
color=#663300>));</FONT></B><BR>tbmPhoto<B><FONT
color=#663300>-></FONT></B>Bitmap<B><FONT
color=#663300>(</FONT></B> THUMBNAIL_WIDTH<B><FONT
color=#663300>,</FONT></B> THUMBNAIL_HEIGHT<B><FONT
color=#663300>,</FONT></B> PixelFormat24bppRGB<B><FONT
color=#663300> );</FONT></B><I><FONT
color=#999999> // initialize variable<BR></FONT></I>Bitmap<B><FONT
color=#663300>*</FONT></B> bmPhoto<B><FONT
color=#663300> =</FONT></B> tbmPhoto<B><FONT
color=#663300>;</FONT></B><BR>但是现在,由于DEBUG_NEW使用的是被重载的<FONT
color=#990000>operator new</FONT>:<FONT
color=#ff6633><BR>void</FONT><B><FONT
color=#663300>*</FONT></B> AFX_CDECL<FONT
color=#990000> operator new</FONT><B><FONT
color=#663300>(</FONT></B>size_t nSize<B><FONT
color=#663300>,</FONT></B> LPCSTR lpszFileName<B><FONT
color=#663300>,</FONT></B><FONT
color=#ff6633> int</FONT> nLine<B><FONT
color=#663300>);</FONT></B><BR>上述代码等价于:<BR>Bitmap<B><FONT
color=#663300>*</FONT></B> tbmPhoto<B><FONT
color=#663300> = (</FONT></B>Bitmap<B><FONT
color=#663300>*)</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#990000>sizeof</FONT><B><FONT
color=#663300>(</FONT></B>Bitmap<B><FONT
color=#663300>),</FONT></B> __FILE__<B><FONT
color=#663300>,</FONT></B> __LINE__<B><FONT
color=#663300>);</FONT></B><BR>tbmPhoto<B><FONT
color=#663300>-></FONT></B>BitmapBitmap<B><FONT
color=#663300>(</FONT></B> THUMBNAIL_WIDTH<B><FONT
color=#663300>,</FONT></B> THUMBNAIL_HEIGHT<B><FONT
color=#663300>,</FONT></B> PixelFormat24bppRGB<B><FONT
color=#663300> );</FONT></B><I><FONT
color=#999999> // initialize variable<BR></FONT></I>Bitmap<B><FONT
color=#663300>*</FONT></B> bmPhoto<B><FONT
color=#663300> =</FONT></B> tbmPhoto<B><FONT
color=#663300>;</FONT></B><BR>回过头来看gdiplus<B><FONT
color=#663300>.</FONT></B>h中的<FONT
color=#990000>operator new</FONT>的声明(在GdiplusBase<B><FONT
color=#663300>.</FONT></B>h中):<FONT
color=#990000><BR>class</FONT> GdiplusBase<B><FONT
color=#663300><BR>{</FONT></B><FONT
color=#990000><BR>public</FONT><B><FONT
color=#663300>:</FONT></B><FONT
color=#ff6633><BR> void</FONT><B><FONT
color=#663300> (</FONT></B><FONT
color=#990000>operator delete</FONT><B><FONT
color=#663300>)(</FONT></B><FONT color=#ff6633>void</FONT><B><FONT
color=#663300>*</FONT></B> in_pVoid<B><FONT
color=#663300>)<BR> {</FONT></B><BR> DllExports<B><FONT
color=#663300>::</FONT></B>GdipFree<B><FONT
color=#663300>(</FONT></B>in_pVoid<B><FONT
color=#663300>);<BR> }</FONT></B><FONT
color=#ff6633><BR> void</FONT><B><FONT
color=#663300>* (</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>)(</FONT></B>size_t in_size<B><FONT
color=#663300>)<BR> {</FONT></B><FONT
color=#ff0000><BR> return</FONT> DllExports<B><FONT
color=#663300>::</FONT></B>GdipAlloc<B><FONT
color=#663300>(</FONT></B>in_size<B><FONT
color=#663300>);<BR> }</FONT></B><FONT
color=#ff6633><BR> void</FONT><B><FONT
color=#663300> (</FONT></B><FONT
color=#990000>operator delete</FONT><B><FONT
color=#663300>[])(</FONT></B><FONT color=#ff6633>void</FONT><B><FONT
color=#663300>*</FONT></B> in_pVoid<B><FONT
color=#663300>)<BR> {</FONT></B><BR> DllExports<B><FONT
color=#663300>::</FONT></B>GdipFree<B><FONT
color=#663300>(</FONT></B>in_pVoid<B><FONT
color=#663300>);<BR> }</FONT></B><FONT
color=#ff6633><BR> void</FONT><B><FONT
color=#663300>* (</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>[])(</FONT></B>size_t in_size<B><FONT
color=#663300>)<BR> {</FONT></B><FONT
color=#ff0000><BR> return</FONT> DllExports<B><FONT
color=#663300>::</FONT></B>GdipAlloc<B><FONT
color=#663300>(</FONT></B>in_size<B><FONT
color=#663300>);<BR> }<BR>};</FONT></B><BR>它重载了<FONT
color=#990000>operator new</FONT>,并且没有提供一个可以容纳<FONT
color=#999900>3</FONT>个参数的<FONT
color=#990000>operator new</FONT>,同时基于这样一个事实:<BR>不同命名域(指全局命名空间与有名命名空间之间,父类与子类,全局与类内部)内进行重载时,下一级的命名空间会覆盖掉上一级的定义,除非显示调用上一级的定义。<BR>因此,全局的重新定义的<FONT
color=#990000>operator new</FONT>并不能用于Bitmap类。也正因为这一原因,编译器会报告:<BR>Bitmap<B><FONT
color=#663300>*</FONT></B> tbmPhoto<B><FONT
color=#663300> = (</FONT></B>Bitmap<B><FONT
color=#663300>*)</FONT></B>Bitmap<B><FONT
color=#663300>::</FONT></B><FONT
color=#990000>operator new</FONT><B><FONT
color=#663300>(</FONT></B><FONT color=#990000>sizeof</FONT><B><FONT
color=#663300>(</FONT></B>Bitmap<B><FONT
color=#663300>),</FONT></B> __FILE__<B><FONT
color=#663300>,</FONT></B> __LINE__<B><FONT
color=#663300>);</FONT></B><BR>error C2660<B><FONT
color=#663300>:</FONT></B><FONT
color=#009900> 'new'</FONT><B><FONT
color=#663300> :</FONT></B> function does<FONT
color=#990000> not</FONT> take<FONT
color=#999900> 3</FONT> parameters<BR>知道了这一点,要修正这一问题,只需给<FONT
color=#990000>class</FONT> GdiplusBase多重载几个<FONT
color=#990000>operator new</FONT>即可。修正后的<FONT
color=#990000>class</FONT> GdiplusBase如下:<FONT
color=#000099><BR>#ifdef _DEBUG<BR></FONT><FONT
color=#990000><BR>namespace</FONT> Gdiplus<B><FONT
color=#663300><BR>{</FONT></B><FONT
color=#990000><BR> namespace</FONT> DllExports<B><FONT
color=#663300><BR> {</FONT></B><FONT
color=#000099><BR> #include <GdiplusMem.h><BR></FONT><B><FONT
color=#663300> };</FONT></B><FONT
color=#000099><BR><BR> #ifndef _GDIPLUSBASE_H<BR> #define _GDIPLUSBASE_H<BR></FONT><FONT
color=#990000> class</FONT> GdiplusBase<B><FONT
color=#663300><BR> {</FONT></B><FONT
color=#990000><BR> public</FONT><B><FONT
color=#663300>:</FONT></B><FONT
color=#ff6633><BR> void</FONT><B><FONT
color=#663300> (</FONT></B><FONT
color=#990000>operator delete</FONT><B><FONT
color=#663300>)(</FONT></B><FONT color=#ff6633>void</FONT><B><FONT
color=#663300>*</FONT></B> in_pVoid<B><FONT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -