`
izuoyan
  • 浏览: 9221914 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

overload new and delete operators

阅读更多

Expertise: Advanced
Language: C++
April 6, 1999
Overload New and Delete in a Class
It is possible to override the global operators new and delete for a given class. For example, you can use this technique to override the default behavior of operator new in case of a failure. Instead of throwing a std::bad_alloc exception, the class-specific version of new throws a char array:

#include <cstdlib> //declarations of malloc and free
#include <new>
#include <iostream>
using namespace std;

class C {
public:
C();
void* operator new (size_t size); //implicitly declared as a static member function
void operator delete (void *p); //implicitly declared as a static member function
};

void* C::operator new (size_t size) throw (const char *){
void * p = malloc(size);
if (p == 0) throw "allocation failure"; //instead of std::bad_alloc
return p;
}

void C::operator delete (void *p){
C* pc = static_cast<C*>(p);
free(p);
}

int main() {
C *p = new C; // calls C::new
delete p; // calls C::delete
}

Note that the overloaded new and delete implicitly invoke the object's constructor and destructor, respectively. Remember also to define a matching operator delete when you override operator new.
关于原来的new operator如何定义的,我们可以试着参考下面一篇短文来得到一些启示:

An FDIS compliant Operator "new"
Rating: none

Ray Brown (view profile)
February 13, 1999

Microsoft KB article Q167733 points out that Visual C++'s implementation of operator new adopts non-FDIS compliant behavior in that it does not throw an exception in the case of an allocation failure. This may cause problems if not with your own code, then with third-party C++ code that becomes merged into your translation units. Third-party inline and template functions are especially susceptible to malfunction under the non-FDIS compliant semantics. In fact, Microsoft's own STL implementation will fail should new ever return NULL; its allocator does not expect this.

The KB article suggests a workaround that involves calling _set_new_handler. This is a good solution if you link statically with the C/C++ runtime library. But static linking is often an unpopular option among C++ developers on the Win32 platform as it increases module size and can cause a variety of other difficulties (e.g., KB Q126646, Q193462). Calling _set_new_handler from a module which links dynamically with the CRT can cause other difficulties, however, as the new handler is kept in a global variable by the CRT. Different modules in a process might thus attempt to install different new handlers, and failures will result.
(continued)

A naive FDIS compliant implementation of operator new, which might resort to malloc or some other low-level allocation routine, has the disadvantage of changing the behavior of new on the Win32 platform, especially when it comes to diagnostic support in debug mode. Unfortunately, from our own implementation of new we cannot now call CRT's new, since it becomes hidden as the compiler and linker resolve new to our own implementation. In addition, we cannot simply copy the CRT's implementation as it makes use of CRT functions that are not exported.

In what follows we present an implementation of ::operator new that does not suffer from any of the problems outlined above. This solution's key consists of locating CRT's operator new address dynamically, and avoiding the repeated overhead of module search through the use of a static object.

Note that if your module links with MFC, then you should not adopt this solution. MFC provides its own operator new, which throws a CMemoryException* on allocation failure. This is necessary as MFC exception handlers expect all exceptions to be derived from MFC's CException base class. While this has the potential of upsetting third-party code for similar reasons as the FDIS non-compliance mentioned above, such code often works as long as some exception is thrown from new and NULL is never returned. Microsoft's STL appears to fall in this category. Code which expects std::bad_alloc on new failure cannot co-exist peacefully with MFC in a module.


----------
// StdNew.cpp
/*
   Adding this file to a project or, preferred when possible, linking with
   StdNew.obj from a subproject causes the ::operator new
   to assume standard FDIS C++ behavior: the operator will throw
   std::bad_alloc on failure and never return NULL.

   You will not want to link with this file from an MFC project, since the
   MFC library requires that a different exception be thrown on failure and
   arranges for such behavior.

   Note: we choose this approach over setting the new handler, since the new
         handler function is kept in the runtime library on a per-process
         basis. Attempting to control the handler could thus lead to
         contention among dll's that each link dynamically to the runtime
         library.
*/

#include "stdafx.h"

#ifdef _AFX
#error ANSI operator new must not be used in MFC project
#endif

#ifndef _MSC_VER
#error This implementation of ANSI operator new is appropriate for Win32 platforms only
#endif

#ifndef _DLL
#error Project must link dynamically with the C++ runtime library
#endif

class COpNewCrtCacher
{
    COpNewCrtCacher();
    COpNewCrtCacher(const COpNewCrtCacher&);                // not impl
    COpNewCrtCacher& operator = (const COpNewCrtCacher&);   // not impl

public:
    typedef void* (__cdecl *t_OpNewFcn)(size_t);
    static t_OpNewFcn GetCrtOpNew();

private:
    static t_OpNewFcn s_pfCrtOpNew;

    // The following static object ensures that GetCrtOpNew is called during
    // module initialization time and hence threading issues do not arise
    // when multiple threads may call into ::operator new simultaneously
    static COpNewCrtCacher s_GlobalModuleOpNewCrtCacherInitializer;
};

COpNewCrtCacher::COpNewCrtCacher()
{
    // Cached pointer to Crt operator new is set when the static object is
    // constructed or when someone calls ::operator new, whichever comes
    // first. In either case, we avoid threading issues.
    GetCrtOpNew();
}

/*
   This member function along with s_pfCrtOpNew are static so that they can
   continue to be used past the time of destruction of the static object.
*/
COpNewCrtCacher::t_OpNewFcn COpNewCrtCacher::GetCrtOpNew()
{
    if (s_pfCrtOpNew)
        return s_pfCrtOpNew;

    // Name of C++ run time library dll
#   ifdef _DEBUG
    const LPCTSTR sCrtName = _T("MSVCRTD.DLL");
#   else
    const LPCTSTR sCrtName = _T("MSVCRT.DLL");
#   endif

    // Get Crt handle
    HMODULE hCrt = GetModuleHandle(sCrtName);
    _ASSERTE (hCrt);

    // Retrieve function pointer to Crt operator new
    s_pfCrtOpNew = reinterpret_cast <t_OpNewFcn>
                   (GetProcAddress(hCrt, "??2@YAPAXI@Z"));
    _ASSERTE (s_pfCrtOpNew);

    return s_pfCrtOpNew;
}

COpNewCrtCacher::t_OpNewFcn COpNewCrtCacher::s_pfCrtOpNew;
COpNewCrtCacher COpNewCrtCacher::s_GlobalModuleOpNewCrtCacherInitializer;

void* __cdecl operator new(size_t nSize) throw(std::bad_alloc)//~~~~~这个地方是定义方式
{
    // Call the operator new in the Crt
    void* pResult = COpNewCrtCacher::GetCrtOpNew()(nSize);

    // If it returned NULL, throw the exception
    if (! pResult)
        throw std::bad_alloc();

    // Otherwise return pointer to allocated memory
    return pResult;
}

<!--content_stop-->

Microsoft KB article Q167733 points out that Visual C++'s implementation of operator new adopts non-FDIS compliant behavior in that it does not throw an exception in the case of an allocation failure. This may cause problems if not with your own code, then with third-party C++ code that becomes merged into your translation units. Third-party inline and template functions are especially susceptible to malfunction under the non-FDIS compliant semantics. In fact, Microsoft's own STL implementation will fail should new ever return NULL; its allocator does not expect this.

The KB article suggests a workaround that involves calling _set_new_handler. This is a good solution if you link statically with the C/C++ runtime library. But static linking is often an unpopular option among C++ developers on the Win32 platform as it increases module size and can cause a variety of other difficulties (e.g., KB Q126646, Q193462). Calling _set_new_handler from a module which links dynamically with the CRT can cause other difficulties, however, as the new handler is kept in a global variable by the CRT. Different modules in a process might thus attempt to install different new handlers, and failures will result.
(continued)

A naive FDIS compliant implementation of operator new, which might resort to malloc or some other low-level allocation routine, has the disadvantage of changing the behavior of new on the Win32 platform, especially when it comes to diagnostic support in debug mode. Unfortunately, from our own implementation of new we cannot now call CRT's new, since it becomes hidden as the compiler and linker resolve new to our own implementation. In addition, we cannot simply copy the CRT's implementation as it makes use of CRT functions that are not exported.

In what follows we present an implementation of ::operator new that does not suffer from any of the problems outlined above. This solution's key consists of locating CRT's operator new address dynamically, and avoiding the repeated overhead of module search through the use of a static object.

Note that if your module links with MFC, then you should not adopt this solution. MFC provides its own operator new, which throws a CMemoryException* on allocation failure. This is necessary as MFC exception handlers expect all exceptions to be derived from MFC's CException base class. While this has the potential of upsetting third-party code for similar reasons as the FDIS non-compliance mentioned above, such code often works as long as some exception is thrown from new and NULL is never returned. Microsoft's STL appears to fall in this category. Code which expects std::bad_alloc on new failure cannot co-exist peacefully with MFC in a module.


----------
// StdNew.cpp
/*
   Adding this file to a project or, preferred when possible, linking with
   StdNew.obj from a subproject causes the ::operator new
   to assume standard FDIS C++ behavior: the operator will throw
   std::bad_alloc on failure and never return NULL.

   You will not want to link with this file from an MFC project, since the
   MFC library requires that a different exception be thrown on failure and
   arranges for such behavior.

   Note: we choose this approach over setting the new handler, since the new
         handler function is kept in the runtime library on a per-process
         basis. Attempting to control the handler could thus lead to
         contention among dll's that each link dynamically to the runtime
         library.
*/

#include "stdafx.h"

#ifdef _AFX
#error ANSI operator new must not be used in MFC project
#endif

#ifndef _MSC_VER
#error This implementation of ANSI operator new is appropriate for Win32 platforms only
#endif

#ifndef _DLL
#error Project must link dynamically with the C++ runtime library
#endif

class COpNewCrtCacher
{
    COpNewCrtCacher();
    COpNewCrtCacher(const COpNewCrtCacher&);                // not impl
    COpNewCrtCacher& operator = (const COpNewCrtCacher&);   // not impl

public:
    typedef void* (__cdecl *t_OpNewFcn)(size_t);
    static t_OpNewFcn GetCrtOpNew();

private:
    static t_OpNewFcn s_pfCrtOpNew;

    // The following static object ensures that GetCrtOpNew is called during
    // module initialization time and hence threading issues do not arise
    // when multiple threads may call into ::operator new simultaneously
    static COpNewCrtCacher s_GlobalModuleOpNewCrtCacherInitializer;
};

COpNewCrtCacher::COpNewCrtCacher()
{
    // Cached pointer to Crt operator new is set when the static object is
    // constructed or when someone calls ::operator new, whichever comes
    // first. In either case, we avoid threading issues.
    GetCrtOpNew();
}

/*
   This member function along with s_pfCrtOpNew are static so that they can
   continue to be used past the time of destruction of the static object.
*/
COpNewCrtCacher::t_OpNewFcn COpNewCrtCacher::GetCrtOpNew()
{
    if (s_pfCrtOpNew)
        return s_pfCrtOpNew;

    // Name of C++ run time library dll
#   ifdef _DEBUG
    const LPCTSTR sCrtName = _T("MSVCRTD.DLL");
#   else
    const LPCTSTR sCrtName = _T("MSVCRT.DLL");
#   endif

    // Get Crt handle
    HMODULE hCrt = GetModuleHandle(sCrtName);
    _ASSERTE (hCrt);

    // Retrieve function pointer to Crt operator new
    s_pfCrtOpNew = reinterpret_cast <t_OpNewFcn>
                   (GetProcAddress(hCrt, "??2@YAPAXI@Z"));
    _ASSERTE (s_pfCrtOpNew);

    return s_pfCrtOpNew;
}

COpNewCrtCacher::t_OpNewFcn COpNewCrtCacher::s_pfCrtOpNew;
COpNewCrtCacher COpNewCrtCacher::s_GlobalModuleOpNewCrtCacherInitializer;

void* __cdecl operator new(size_t nSize) throw(std::bad_alloc)//~~~~~这个地方是定义方式
{
    // Call the operator new in the Crt
    void* pResult = COpNewCrtCacher::GetCrtOpNew()(nSize);

    // If it returned NULL, throw the exception
    if (! pResult)
        throw std::bad_alloc();

    // Otherwise return pointer to allocated memory
    return pResult;
}

<!--content_stop-->

分享到:
评论

相关推荐

    overload and override.txt的区别

    ### Overload 和 Override 的区别 在面向对象编程中,`overload`(重载)与`override`(重写或覆盖)是两个重要的概念。它们虽然只有一字之差,但在实际应用中却有着本质的区别。 #### Overload(重载) 重载指的...

    overload and override

    ### Overload和Override详解 #### 一、概念概述 在面向对象编程中,尤其是在Java语言中,`Overload`(重载)和`Override`(重写)是两个非常重要的概念,它们帮助开发者更好地组织代码并提高代码的复用性和灵活性...

    android逆向之frida脚本中overload带的参数.pdf

    通过正确地使用`.overload()`,我们可以确保Frida正确地识别和hook到目标方法,而不会因为方法重载而引发错误。这在逆向工程中尤其有用,因为它允许我们精确地控制要拦截和分析的代码路径。 总之,本文深入探讨了...

    information_overload

    information_overload

    PyPI 官网下载 | python-overload-0.0.1.tar.gz

    《Python-overload库详解》 在Python编程中,动态类型是其一大特色,但也因此在某些情况下可能导致代码可读性和可维护性降低。为了解决这个问题,Python社区开发了多种工具,其中`overload`库就是一个重要的解决...

    Tech overload BRK

    - **字体分类**:字体通常分为衬线(如Times New Roman)、无衬线(如Arial)、手写体和装饰性字体。"Tech overload BRK"可能是装饰性字体,因其名称含有“Overload”,可能设计得较为复杂或具有科技感。 - **字体...

    Overload.zip

    《Overload:高效XML编辑与管理工具》 在IT领域,XML(eXtensible Markup Language)作为一种重要的数据交换格式,被广泛应用于软件开发、数据分析和网络通信等多个方面。然而,XML文件通常结构复杂,使用普通的...

    Override-Overload

    ### Override与Overload的区别 在面向对象编程中,方法重写(Override)和方法重载(Overload)是两个非常重要的概念。它们虽然都涉及到方法名称的重复使用,但是其本质含义、作用以及应用场景有着明显的区别。 ##...

    Overload

    在IT领域,"Overload"一词通常与编程语言中的函数重载或操作符重载有关。函数重载(Function Overloading)和操作符重载(Operator Overloading)是面向对象编程的重要特性,允许程序员为同一个函数名或操作符定义多...

    Delphi面向对象:overload与override[文].pdf

    Delphi面向对象编程之overload与override Delphi面向对象编程中,overload和override是两个非常重要的概念,它们都是面向对象编程的基础概念。本文将详细介绍overload和override的概念、应用场景及实现方法。 一、...

    perl用overload实现复数运算

    perl用overload重置运算符,实现复数运算,复数用向量表示

    Digital and Analogue Communication Systems 2012.

    Granular Noise and Slope Overload Noise, 201 Adaptive Delta Modulation and Continuously Variable Slope Delta Modulation, 203 Speech Coding, 204 3–9 3–10 3–11 3–12 3–13 Time-Division Multiplexing ...

    面向对象程序设计英文教学课件:07_Operator Overload.ppt

    在C++中,OOP提供了丰富的特性,包括运算符重载(Operator Overload)。运算符重载是C++允许程序员为自定义类型赋予特定操作符新含义的一种机制,使得这些运算符可以用于类的对象,增加了代码的简洁性和可读性。 07...

    overload-decorator:定义装饰器,以leFunc为灵感

    过载装饰器 ... import { overload , defaultOverload } from 'overload-decorator' ; class Calculator { // we can have an overload that accepts two numbers @ overload ( Number , Number )

    Social Recommender Systems Tutorial - 2011

    SRSs also aim at increasing adoption, engagement, and participation of new and existing users of social media sites. Recommendations of content (blogs, wikis, etc.) [5], tags [7], people [3], and ...

    Social Recommender Systems Tutorial - 2011.part2

    SRSs also aim at increasing adoption, engagement, and participation of new and existing users of social media sites. Recommendations of content (blogs, wikis, etc.) [5], tags [7], people [3], and ...

    Java 重写(Override)与重载(Overload).pdf

    根据提供的文件信息,我们可以深入探讨Java中的两个核心概念:重写(Override)与重载(Overload)。这两个概念在面向对象编程中非常重要,尤其是在Java这样的语言中。 ### Java中的重写(Override) #### 什么是重写? ...

    ecmascript.overload2:用于JavaScript函数重载的优雅解决方案

    # Install overload2 and save as a dependency of current package.npm install overload2 --save 打开节点并运行下一个代码: const overload2 = require ( 'overload2' ) ;// Create a function with overload

Global site tag (gtag.js) - Google Analytics