微软VC各版本BUG: error C2660: 'new' : function does not take 3 parameters[转]

2024-01-06 01:58

本文主要是介绍微软VC各版本BUG: error C2660: 'new' : function does not take 3 parameters[转],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天在用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
#ifdef _DEBUG
//#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE [] = __FILE__;
#endif
建议法二:在GdiplusBase.h文件中 class GdiplusBase中添加如下代码
 //
 void * (operator new)(size_t nSize, LPCSTR lpszFileName, int nLine)
 {
  return DllExports::GdipAlloc(nSize);
 }
 
 void operator delete(void* p, LPCSTR lpszFileName, int nLine)
 {
  DllExports::GdipFree(p);
 }
 //
下面是转载文章,作者:billdavid
不让用盗版,遂准备逐一将 各软件要么换成开源的,要么就自己写,看了看,就数Acdsee最简单了(有些高级功能根本用不着),行,从这个入手吧。
需求分析:基本的图片查 看功能,图片格式转换功能,基本的图形变换功能。
技术可行性分析:MS提供的GDI
+ 已经提供了比较专业的图形显示、格式 转换功能,而且简单易用。
....

OK,就绪,开始干吧。

但是在程序编写的过程中,有条错误信息让我很不解。程序中有如下语句:
bmPhoto
 =  new  Bitmap (  THUMBNAIL_WIDTH ,  THUMBNAIL_HEIGHT ,  PixelFormat24bppRGB  );
每次DEBUG编译的时 候总是报告如下的错误:
error C2660
:  'new'  :  function does  not  take  3  parameters
开始以为是Bitmap的构造函数的问题,但是查了一下,Bitmap明明有个构造函 数:
Bitmap
( IN INT width ,
       IN INT height ,
       IN PixelFormat format  =  PixelFormat32bppARGB );
那会是什么问题呢?上网 讨论了一下,最终将问题锁定在MFC程序中的这样一个宏定义上:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static  char  THIS_FILE [] =  __FILE__ ;
#endif
这几行从来都不会引起我们 注意的代码有什么问题呢 ? 为什么会使得我们的代码报告如上所述的编译错误呢 ?
让我们来看看 DEBUG_NEW的定义(在afx . h中):
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)

// Memory tracking allocation
void *  AFX_CDECL  operator new ( size_t nSize ,  LPCSTR lpszFileName ,  int  nLine );
#define DEBUG_NEW new(THIS_FILE, __LINE__)
#if _MSC_VER >= 1200
void  AFX_CDECL  operator delete ( void *  p ,  LPCSTR lpszFileName ,  int  nLine );
#endif
看到这里你可能会想, 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信息。我们的如下代码
int *  pi  =  new  int ;  // the same as int* pi = new int(); or int* pi = new int[1];
等价于
int *  tpi  = ( int *) operator new ( sizeof ( int ));  // attention: this line cannot pass compilation if you have define DEBUG_NEW
int *  pi  =  tpi ;
同理,定义DEBUG_NEW前,文章开头报错的这条语句:
Bitmap
*  bmPhoto  =  new  Bitmap (  THUMBNAIL_WIDTH ,  THUMBNAIL_HEIGHT ,  PixelFormat24bppRGB  );
等价于
Bitmap
*  tbmPhoto  = ( Bitmap *) operator new ( sizeof ( Bitmap ));
tbmPhoto -> Bitmap (  THUMBNAIL_WIDTH ,  THUMBNAIL_HEIGHT ,  PixelFormat24bppRGB  );  // initialize variable
Bitmap *  bmPhoto  =  tbmPhoto ;
但是现在,由于DEBUG_NEW使用的是被重载的 operator new
void *  AFX_CDECL  operator new ( size_t nSize ,  LPCSTR lpszFileName ,  int  nLine );
上述代码等价于:
Bitmap
*  tbmPhoto  = ( Bitmap *) operator new ( sizeof ( Bitmap ),  __FILE__ ,  __LINE__ );
tbmPhoto -> BitmapBitmap (  THUMBNAIL_WIDTH ,  THUMBNAIL_HEIGHT ,  PixelFormat24bppRGB  );  // initialize variable
Bitmap *  bmPhoto  =  tbmPhoto ;
回过头来看gdiplus . h中的 operator new 的声明(在GdiplusBase . h中):
class  GdiplusBase
{

public
:
    void
 ( operator delete )( void *  in_pVoid )
    {

       DllExports :: GdipFree ( in_pVoid );
    }

    void
* ( operator new )( size_t in_size )
    {

       return
 DllExports :: GdipAlloc ( in_size );
    }

    void
 ( operator delete [])( void *  in_pVoid )
    {

       DllExports :: GdipFree ( in_pVoid );
    }

    void
* ( operator new [])( size_t in_size )
    {

       return
 DllExports :: GdipAlloc ( in_size );
    }
};

它重载了 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如下:
#ifdef _DEBUG

namespace
 Gdiplus
{

    namespace
 DllExports
    {

        #include <GdiplusMem.h>
    };

    #ifndef _GDIPLUSBASE_H
    #define _GDIPLUSBASE_H
    class  GdiplusBase
    {

        public
:
            void
 ( operator delete )( void *  in_pVoid )
            {

                DllExports :: GdipFree ( in_pVoid );
            }


            void
* ( operator new )( size_t in_size )
            {

                return
 DllExports :: GdipAlloc ( in_size );
            }


            void
 ( operator delete [])( void *  in_pVoid )
            {

                DllExports :: GdipFree ( in_pVoid );
            }


            void
* ( operator new [])( size_t in_size )
            {

                return
 DllExports :: GdipAlloc ( in_size );
            }


            void
 * ( operator new )( size_t nSize ,  LPCSTR lpszFileName ,  int  nLine )
            {

                return
 DllExports :: GdipAlloc ( nSize );
            }


            void
 operator delete ( void *  p ,  LPCSTR lpszFileName ,  int  nLine )
            {

                DllExports :: GdipFree ( p );
            }

        };

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

最后总结一下,在进 行
operator new 重 载时应注意:
1. new operator 是不可以重载的,可以重载的是 operator new new 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 的实现如下:
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline  void  * __cdecl  operator new ( size_t ,  void  * _P )
    {
return  ( _P ); }
#if     _MSC_VER >= 1200
inline  void  __cdecl  operator delete ( void  *,  void  *)
    {
return ; }
#endif
#endif

附:
(
转贴 ) 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 new operator 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 来实现我们的内存分配方案 .

参考资料:
1. PRB :  Microsoft Foundation Classes DEBUG_NEW Does Not Work with GDI +.  http : //support.microsoft.com/default.aspx?scid=kb;en-us;317799
2. VC ++ 6.0 中内存泄漏检测 .  http : //blog.vckbase.com/bruceteen/archive/2004/10/28/1130.aspx
3. More Effective C ++.  Item  8 :  Understand the different meanings of  new and delete .

这篇关于微软VC各版本BUG: error C2660: 'new' : function does not take 3 parameters[转]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/574859

相关文章

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

conda安装GPU版pytorch默认却是cpu版本

《conda安装GPU版pytorch默认却是cpu版本》本文主要介绍了遇到Conda安装PyTorchGPU版本却默认安装CPU的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、问题描述二、网上解决方案罗列【此节为反面方案罗列!!!】三、发现的根本原因[独家]3.1 p

Redis指南及6.2.x版本安装过程

《Redis指南及6.2.x版本安装过程》Redis是完全开源免费的,遵守BSD协议,是一个高性能(NOSQL)的key-value数据库,Redis是一个开源的使用ANSIC语言编写、支持网络、... 目录概述Redis特点Redis应用场景缓存缓存分布式会话分布式锁社交网络最新列表Redis各版本介绍旧

IIS 7.0 及更高版本中的 FTP 状态代码

《IIS7.0及更高版本中的FTP状态代码》本文介绍IIS7.0中的FTP状态代码,方便大家在使用iis中发现ftp的问题... 简介尝试使用 FTP 访问运行 Internet Information Services (IIS) 7.0 或更高版本的服务器上的内容时,IIS 将返回指示响应状态的数字代

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

查看MySQL数据库版本的四种方法

《查看MySQL数据库版本的四种方法》查看MySQL数据库的版本信息可以通过多种方法实现,包括使用命令行工具、SQL查询语句和图形化管理工具等,以下是详细的步骤和示例代码,需要的朋友可以参考下... 目录方法一:使用命令行工具1. 使用 mysql 命令示例:方法二:使用 mysqladmin 命令示例:方

Java版本不兼容问题详细解决方案步骤

《Java版本不兼容问题详细解决方案步骤》:本文主要介绍Java版本不兼容问题解决的相关资料,详细分析了问题原因,并提供了解决方案,包括统一JDK版本、修改项目配置和清理旧版本残留等步骤,需要的朋... 目录错误原因分析解决方案步骤第一步:统一 JDK 版本第二步:修改项目配置第三步:清理旧版本残留兼容性对

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境