照着MSDN用Bitmap,居然还是没用明白,原来问题在这里....

原创 2011年01月22日 08:26:00

转载:

作者:王继ID:wangji163163

 

 

今天在用GDI+写程序时,有

HatchBrush * brushDotDiamond = new HatchBrush(HatchStyle25Percent,color);
用VC6 SP6或VS2005编译错误为error C2660: 'new' : function does not take 3 parameters
这是VC的一个BUG,微软至今还没有解除。
解决办法如下:
法一:在该CPP文件开头部分注释掉#define new DEBUG_NEW
 
建议法二:在GdiplusBase.h文件中class GdiplusBase中添加如下代码
 
转载:
作者:billdavid

不让用盗版,遂准备逐一将各软件要么换成开源的,要么就自己写,看了看,就数Acdsee最简单了(有些高级功能根本用不着),行,从这个入手吧。
需求分析:基本的图片查看功能,图片格式转换功能,基本的图形变换功能。
技术可行性分析:MS提供的GDI
+已经提供了比较专业的图形显示、格式转换功能,而且简单易用。
....

OK,就绪,开始干吧。

但是在程序编写的过程中,有条错误信息让我很不解。程序中有如下语句:

每次DEBUG编译的时候总是报告如下的错误:
error C2660
: 'new' : function does not take 3 parameters
开始以为是Bitmap的构造函数的问题,但是查了一下,Bitmap明明有个构造函数:

那会是什么问题呢?上网讨论了一下,最终将问题锁定在MFC程序中的这样一个宏定义上:

这几行从来都不会引起我们注意的代码有什么问题呢?为什么会使得我们的代码报告如上所述的编译错误呢?
让我们来看看DEBUG_NEW的定义(在afx.h中):

看到这里你可能会想,new被define成了DEBUG_NEW,而后者又被define成了new(...),这不是成了个循环?非也。由于afx.h早于任何其它头文件被包含(stdafx.h包含afxwin.h,afxwin.h又包含了afx.h,而MFC要求我们在任何有效代码之前包含stdafx.h,当然,这不是必须的),所以DEBUG_NEW的定义早于后面的#define new DEBUG_NEW,也就是说这个define只对后面的代码有效,对前面已经include了的afx.h中的代码是无效的。

上面只是题外话,现在回到正题。
MFC重载
operator new,是为了方便定位内存泄漏,重载后的operator new会记录下所分配的每块内存对应的__FILE__和__LINE__信息。一般来讲,标准的operator new的声明如下:
void *__cdecl operator new(size_t);
即它只有一个参数,只接收一个size信息。我们的如下代码

同理,定义DEBUG_NEW前,文章开头报错的这条语句:
Bitmap
* bmPhoto = new Bitmap( THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, PixelFormat24bppRGB );
等价于

但是现在,由于DEBUG_NEW使用的是被重载的operator new
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
上述代码等价于:

回过头来看gdiplus.h中的operator new的声明(在GdiplusBase.h中):

它重载了operator new,并且没有提供一个可以容纳3个参数的operator new,同时基于这样一个事实:
不同命名域(指全局命名空间与有名命名空间之间,父类与子类,全局与类内部)内进行重载时,下一级的命名空间会覆盖掉上一级的定义,除非显示调用上一级的定义。
因此,全局的重新定义的
operator new并不能用于Bitmap类。也正因为这一原因,编译器会报告:
Bitmap
* tbmPhoto = (Bitmap*)Bitmap::operator new(sizeof(Bitmap), __FILE__, __LINE__);
error C2660: 'new' : function does not take 3 parameters
知道了这一点,要修正这一问题,只需给
class GdiplusBase多重载几个operator new即可。修正后的class GdiplusBase如下:

OK,问题已解决,其实这只是个重载operator new的问题,但这个问题由于DEBUG_NEW这个不起眼的宏,倒还真变得有点复杂。

最后总结一下,在进行
operator new重载时应注意:
1.new operator是不可以重载的,可以重载的是operator newnew operator 首先调用 operator new,然后调用构造函数(如果有的话)。new operator的这个行为是不可以重载的,可以重载的仅仅是operator new,也就是内存分配。
2.重载operator new是一件必须十分小心的事情,在编写MFC程序或者你所编写的系统重载了全局的operator new时,尤其需要注意,同时应注意所有的#include头文件最好添加在所有define之前,以免造成受到后续对new的重定义的影响。你可以尝试在你的MFC程序的#define new DEBUG_NEW一句之后,添加#include <vector>,你会收到一大堆莫名奇妙的错误提示(DEBUG编译时才有),这正是由于#define new DEBUG_NEW和后面的static char THIS_FILE[] = __FILE__;造成的影响。
3.operator new/delete在性质上类似于静态函数,你可以直接通过类名来访问它们。
4.理解了operator new的基本概念,要理解头文件NEW中的placement new/delete的实现也就不是什么难事了,头文件NEW中的placement new/delete的实现如下:

附:
(
转贴)C++的各种new简介

1.new T

第一种
new最简单,调用类的(如果重载了的话)或者全局的operator new分配空间,然后用类型后面列的参数来调用构造函数,用法是
new TypeName(initial_args_list).
如果没有参数,括号一般可以省略.例如

int *p=new int;
int
 *p=new int(10);
int
 *p=new foo("hello");

通过调用delete来销毁:
delete
 p;

2.
 new T[]
这种new用来创建一个动态的对象数组,他会调用对象的operator new[]来分配内存(如果没有则调用operator new,搜索顺序同上),然后调用对象的31m默认构造函数初始化每个对象用法:
new
 TypeName[num_of_objects];
例如
int *p= new int[10];
销毁时使用operator delete31m[]

3.
new()T 和new() T[]
这是个带参数的new,这种形式的new会调用operator new(size_t,OtherType)来分配内存,这里的OtherType要和new括号里的参数的类型兼容,这种语法通常用来在某个特定的地址构件对象,称为placement new,前提是operator new(size_t,void*)已经定义,通常编译器已经提供了一个实现,包含<new>头文件即可,这个实现只是简单的把参数的指定的地址返回,因而new()运算符就会在括号里的地址上创建对象.
需要说明的是,第二个参数不是一定要是void*,可以识别的合法类型,这时候由C++的重载机制来决定调用那个operator new.

当然,我们可以提供自己的operator new(size_,Type),来决定new的行为,比如
char data[1000][sizeof(foo)];
inline
 void* operator new(size_t ,int n)
{

        return
 data[n];
}


就可以使用这样有趣的语法来创建对象:
foo *p=new(6) foo(); //把对象创建在data的第六个单元上的确很有意思
标准库还提供了一个nothrow的实现:
void
* operator new(std::size_t, const std::nothrow_t&) throw();
void
* operator new[](std::size_t, const std::nothrow_t&) throw();

就可以实现调用new失败时不抛出异常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一个实例

placement new 创建的对象不能直接delete来销毁,而是要调用对象的析够函数来销毁对象,至于对象所占的内存如何处理,要看这块内存的具体来源.

4.
 operator new(size_t)
这个的运算符分配参数指定大小的内存并返回首地址,可以为自定义的类重载这个运算符,方法就是在类里面声明加上
void *operator new(size_t size)
{

        //在这里分配内存并返回其地址
}
无论是否声明,类里面重载的各种operator newoperator delete都是具有static属性的.

一般不需要直接调用operator new,除非直接分配原始内存(这一点类似于C的malloc),在冲突的情况下要调用全局的operator加上::作用域运算符:
::
operator new(1000); // 分配1000个31m字节

返回的内存需要回收的话,调用对应的operator delete

5.
operator new[](size_t)

这个也是分配内存,,只不过是专门针对数组,也就是new T[]这种形式,当然,需要时可以显式调用

6.operator new(size_t size, OtherType other_value)
operator new[](size_t size, OtherType other_value)
参见上面的new()

需要强调的是,new用来创建对象并分配内存,它的行为是不可改变的,可以改变的是各种operator new,我们就可以通过重载operator new来实现我们的内存分配方案.

 

相关文章推荐

C#开发日志[2013-12-5]创建Bitmap引发"参数无效"异常

今天碰到一个异常,在 Bitmap bmp = new Bitmap((int)m_nWidth, (int)m_nHeight, bmpFormat); 时,引发"参数无效"的异常。 后面发现,进程...

#include <gdiplus.h>出错

参考文章:http://bbs.csdn.net/topics/80482502?list=lz xxx\GdiPlusImaging.h(67) : error C2501: “MIDL_IN...

ASP.NET MVC 音乐商店完整项目示例

MusicStore 项目的完整配套视频! 这是一个系列文章,原文内容出自微软的 MusicStore。 首先对原文内容进行了简单的翻译,以方便大家参考,另外对于其中的部分内容,也进行...

c# GDI+ Image.Save()或者Bitmap.Save()方法保存高质量图片

GDI+保存质量比较高的图片的方法,使用Image或者Bitmap的Save方法调节图像保存的质量。 Image.Save方法共有五种重载  其中Save(String, ImageCod...

详解win7中的文件属性“访问时间”和“修改时间”不一致的原因分析 【原来LastAccessTime早就没用了】

原帖地址 http://www.xueit.com/html/2010-07/44-4818641862010712104126890.html 注:wp7的文件系统同样适应,即wp7中的Isola...

有问题的工程,在这里,谢谢了

  • 2011年07月15日 00:47
  • 13.61MB
  • 下载

房间分配问题,没用多核技术

  • 2007年12月26日 18:28
  • 6KB
  • 下载

【正一专栏】读《摆渡人》——原来你在这里

读《摆渡人》——原来你在这里 世界上真的有灵魂吗?小的时候有时候一个人发呆,总是想一些世界,尤其是关于宇宙的,100年后世界会变成什么样子,那个时候我已经不在了,但是我的灵魂...

谈薪你有这些问题,谈了也没用!

总是嫌公司开价低?你有没有想过,其实根本不是人家开价低,而是你不会谈薪!注意了,谈薪时犯了这些错误,薪水高了就怪了!  原因一:勇气不足    “不知道要如何开口”是在前程无忧论坛上“...

一个最新发现,原来程序员的最终归宿在这里

原文地址:http://www.cnblogs.com/zuoxiaolong/p/life46.html 地狱      在北京生活的时候,LZ每天都在琢磨一些生活上未来必须要面对的事。没...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:照着MSDN用Bitmap,居然还是没用明白,原来问题在这里....
举报原因:
原因补充:

(最多只允许输入30个字)