Skip to content

Latest commit

 

History

History
157 lines (130 loc) · 4.43 KB

cpp_new_delete.md

File metadata and controls

157 lines (130 loc) · 4.43 KB
title date categories tags
用c++模板来展示new与delete操作符原理
2009-06-08
技术
c++

C++中的new与delete可以认为是C中的malloc与free的升级版本。new包含两部分:

  • 第一部分是与malloc功能相同,是从堆上面申请内存块
  • 第二部是调用类的构造方法来初始化刚申请的内存。

delete是new的逆过程,先调用类的析构方法来反初始化,再把刚申请的内存还给堆。

new []与delete []是针对数组操作符,要注意是通过new []分配的对象,不能用delete来释放对象,否则会有内存泄漏。当然通过new分配的对象,不能用delete[]来释放对象。后面我会通过代码来说明为什么。

下面是C++ 中的new与delete函数原型,申请内存失败会抛出异常bad_alloc

void* operator new(std::size_t) throw (std::bad_alloc);
void* operator new[](std::size_t) throw (std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();

使用举例:

int* p1 = new int();
delete p2;

int* p2 = new int[5];
delete [] p2;

终于到了用模板来模拟new与delete操作符,代码中有注释说明,其中对于调用类的构造方法,采用一种C++标准中称作in-place construtor的方式。使用原型为T* = new(pbuff) T(),直译的话就是在pbuff这块内存构造T类,而不用再去堆上面申请内存。这种技巧大量应用在对象池的实现中,即pbuff这块内存可以挂在链表中反复地使用(这里先不展开说了)。

/**
 * A simulation of c++ new T() & new T(param) operation
 */  
struct NewObj {
    template <typename T>
    inline void operator()(T*& pObj) {
        // allocate memory form heap
        void * pBuff = malloc(sizeof(T));
        // call constructor
        pObj = new (pBuff) T();
    }

    template <typename T, typename P>
    inline void operator()(T*& pObj, const P& param) {
        // allocate memory form heap
        void * pBuff = malloc(sizeof(T));
        // call constructor, pass one param
        pObj = new(pBuff) T(param);
    }
};  

/**
 * A simulation of c++ delete T operation
 */  
struct DeleteObj {  
    template <typename T>  
    inline void operator()(T*& pObj) {  
        if ( NULL == pObj ) { return ;}  
        // call destructor  
        pObj->~T();  
        // free memory to heap  
        free((void*)pObj);  
        pObj = NULL;  
    }  
};  

/**
 * A simulation of c++ new T[N]() operation
 */  
struct NewObjArray {  
    template <typename T>  
    inline void operator()(T*& pObj, unsigned int size) {  
        // save the number of array elements in the beginning of the space.  
        long * pBuff = (long *) malloc (sizeof(T) * size + sizeof(long));  
        *((unsigned int *) pBuff) = size;  
        pBuff++;  

        // change pointer to T type, then can use pT++  
        T * pT = (T *) pBuff;  
        // save the pointer to the start of the array.  
        pObj = pT;  
        // now iterate and construct every object in place.  
        for (unsigned int i = 0; i < size; i++) {  
            new((void *) pT) T();  
            pT++;  
        }  
    }  
};  


/**
 * A simulation of c++ delete [] T operation
 */  
struct DeleteObjArray {  
    template <typename T>  
    inline void operator()(T*& pObj) {  
        unsigned int size = *((unsigned int *) ((long *) pObj - 1));  

        T * pT = pObj;  
        // call destructor on every element in the array.  
        for (unsigned int i = 0; i < size; i++) {  
            pT->~T();  
            pT++;  
        }  
        // free memory to heap.  
        free ((void *) ((long *) pObj - 1));  
        pObj = NULL;  
    }  
};  

测试代码:

struct TestClass {  
    TestClass() : mem1(0), mem2(0)  {}  

    TestClass(int m) : mem1(m), mem2(0) {}  
  
    int mem1;  
    long mem2;  
};  

void test_new_delete()  {  
    TestClass* p1 = NULL;  
    NewObj()(p1);  
    printf("%p/n", p1);  
    DeleteObj()(p1);  

    //  
    TestClass* p2 = NULL;  
    NewObj()(p2, 0);  
    printf("%p/n", p2);  
    DeleteObj()(p2);  

    //  
    TestClass* p3 = NULL;  
    NewObjArray()(p3, 5);  
    printf("%p/n", p3);  
    DeleteObjArray()(p3);  
}  

测试环境为eclipse+cdt+ubuntu+gcc,注意头文件需要#include<new>,使用#include<stdlib.h>会导致编译不过,因为in-place construtor是C++中的新玩意。