New运算符的重载

原创 2014年01月16日 15:32:07
首先我们要清楚,为什么我们要重载new,和delete了?这还不是指针造成的,确实指针是一件让人喜欢的东西,用起来如此让人喜欢,让人顺手。然而小程序我们完全可以避免内存泄露问题,大程序就不那么容易了,然而我们有一种特别好的方法可以跟踪我们new,和delete动作,找到未被释放的内存。办法是什么呢?微软给我们提供了一种很好的方法,那就是重载new,和delete。

       在实现之前我们要清楚new,和delete的工作机理,这是个多么好的学习机会啊!

       对与new操作符,其实和sizeof一样,都是c++内置的,然而像strlen就不是了,strlen属于函数。对于new的功能我们是没有办法改变的,当我们new一个对象时,new为我们做了两件事情,一、申请一块足够的内存空间供存放对象,对于new一个数组对象,编译器会计算出总共的空间,然后执行类似c语言中malloc函数类似的功能。二、初始化对象,对于单个对象,包括包括基本对象和类对象,可以通过括号初始化,比如int * pn = new int(3); A * pa = new A(3);   然而对于数组不能初始化,对于类对象,必须定义无参数的构造函数。对与new的基本功能我们是无法改变的。

       我们所能改变的就是如何为对象分配内存,我们可一重载这个函数以实现分配内存。通常的重载方式是:

       void * operator new (size_t size);

       然而这已经足够了,在一般的operator new 重载函数里,我们可以再加入其它参数,但第一个参数必须是size_t类型,即为无符号整形。正是有这种特性,为我们对内存申请和释放的跟踪提供了可能。


       具体实现就是第一个operator new 的重载函数,我们第一的这个函数是这样的:

void * operator new(unsigned int size, const char *file, int line)
{
    cout << "new size:" << size << endl;
    cout << file << " " << line << endl;

    void * p = malloc(size);

    return p;
}

       然后用宏替换所有的new:

#define new new(__FILE__, __LINE__)

       这样我们每次调用new,比如int * pn = new int;被编译器替换成了int * pn = new (__FILE__, __LINE__) int,从而调用我们定义的operator new,这种办法确实很妙。需要交代的是,对于数组同样适用,而是在编译的是后由编译器计算出所需要的长度调用我们定义的operator new函数。

       对于delete,我们无需使用宏定义,只要重载operator delete就可以了,然而我们需要重载两个delete:

void operator delete(void * p)
{
    cout << "delete " << (int)p << endl;
    free(p);
}

void operator delete [] (void * p)
{
    cout << "delete [] " << (int)p << endl;
    free(p);
}


       其实后面一个函数的内容和前面的内容一样,但为了支持数组的释放,我们必须是要定义的。那么我们只是简单的free(p)编译器咋知道我们释放的数组,还是单个对象了,这个不用我们操心了,我们只要提供给free函数一个申请内存的首地址就可以了。因为在用malloc申请的时候,我们也把数组装换为内存大小了。

       由此我们可以得出下面的推断:用int * pn = new int [100];的空间,用delete pn释放和delete [] pn释放效果一样。然而那么既然这两种方式一样,那还要delete [] 干什么,其实delete [] 有另外的作用就是类对象数组的释放,编译器把delete []解释为调用对象的析构函数,这个是通过循环实现的,最后释放掉申请的内存。

       既然我们已经跟踪了new和delete,那么就可以比较容易的判断申请的内存是否最后得到释放,要完成它,我们还需要一个链表,或者其它,当我们申请一块内存的时候加入到链表中,释放一块空间的时候,从链表中删除和释放内存首地址相同的节点就可以了,最后理想的情况是链表为空,如果不为空,那就说明内存发生泄露(Memory leaks)了。

完整代码:

#include "malloc.h"
#include "iostream.h"

#ifdef _DEBUG

void * operator new(unsigned int size, const char *file, int line)
{
    cout << "new size:" << size << endl;
    cout << file << " " << line << endl;

    // 下面两种方法可以达到同样的效果,但下面一种比较好
    // 因为用下面一种可以保持原有的申请方式一样
    //void * p = malloc(size);
    void * p = operator new(size);

    return p;
}

void operator delete(void * p)
{
    cout << "delete " << (int)p << endl;
    free(p);
}

void operator delete [] (void * p)
{
    cout << "delete [] " << (int)p << endl;
    free(p);
}

void operator delete(void * p, const char *file, int line)
{
    cout << "delete file line" << endl;
    free(p);
}

void operator delete [] (void * p, const char *file, int line)
{
    cout << "delete [] file line" << endl;
    free(p);
}

#define new new(__FILE__, __LINE__)
#endif

void main()

重载全局new/delete实现内存检测

下面介绍用重载new/delete运算符的方式来实现一个简单的内存泄露检测工具,基本思想是重载全局new/delete运算符,被检测代码调用new和delete运算符时就会调用重载过的operator...
  • hzyong_c
  • hzyong_c
  • 2010年10月18日 17:38
  • 9506

C++ 内存分配(new,operator new)详解

讲述C++ new关键字和operator new, placement new之间的种种关联,new的底层实现,以及operator new的重载和一些在内存池,STL中的应用。...
  • WUDAIJUN
  • WUDAIJUN
  • 2013年07月09日 14:55
  • 53768

C++的三种new简介及重载局部(类内部)与全局operator new

先简单解释下C++的三种new,由于它们的名字实在是。。我就说的通俗点。1、new运算符(new operator)大哥,我们在代码中直接使用的就是它。它做2件事:调用后两种new申请内存和初始化对象...
  • qq_29227939
  • qq_29227939
  • 2016年06月11日 21:35
  • 3372

重载new和delete的一些规则

重载new和delete的一些规则重载new和delete的一些规则 一般规则 特殊规则1 特殊规则2 特殊规则3 new和delete重载实例 直接获取当前的new_handler 转载请注明出处参...
  • sanoseiichirou
  • sanoseiichirou
  • 2015年11月20日 23:18
  • 1312

c++ new操作符的重载

  • bichenggui
  • bichenggui
  • 2009年11月17日 21:22
  • 7690

关于new 以及操作符重载

1. 操作符重载参加此文  http://www.adintr.com/myarticle/operator.html 2. 内存泄露和检查见此文: 为什么要重载new?作者ariesram电...
  • tedious
  • tedious
  • 2011年09月19日 14:15
  • 1077

C++的new 和 delete 操作符重载。

测试代码: // test.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include using name...
  • chjjunking
  • chjjunking
  • 2014年03月04日 12:16
  • 2764

控制内存分配----重载new和delete & 定位new表达式

定位new表达式, 重载new和delete, 控制内存分配
  • qianqin_2014
  • qianqin_2014
  • 2016年05月05日 11:17
  • 842

【2016/3】C++ 类与对象进阶 运算符重载 new delete 模板 继承

类与对象:const常量哪怕栈空间数据被改 被访问时依然是使用存于符号表的数据构造函数的形式: 拷贝构造 Test(Test &t){} 初始化构造 Test(int ...
  • hsgwpj
  • hsgwpj
  • 2016年03月19日 23:03
  • 633

如何重载new和delete函数

在嵌入式系统中使用C++的一个常见问题是内存分配,即对new 和 delete 操作符的失控。   具有讽刺意味的是,问题的根源却是C++对内存的管理非常的容易而且安全。具体地说,当一个对象被消除时...
  • talentluke
  • talentluke
  • 2011年01月05日 10:36
  • 3027
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:New运算符的重载
举报原因:
原因补充:

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