C++ new/operator new/placement new浅析

更详细见:http://blog.csdn.net/blues1021/article/details/72357672点击打开链接

总结:不要轻易的去重载new, operator new,placement new运算符,因为调用比较复杂(new操作符可隐式也可显式调用)且内部元素个数这些比较难处理,即使是在内存池技术中, 而应该是用包装的方式用宏或者函数调用的方式来实现,效果比较好。 new[],operator new[]数组的方式也不建议使用,用宏或者函数的方式来实现内存的申请初始化,析构释放比较好。

1.new和 operator  new,placement new的区别
不能重载new,new 运算符做两件事情,一是为类申请内存类似malloc,二是调用类的构造函数为对象分配内存并返回对象指针。
只能重载的是operator new,operator new是为类申请内存,很多使用内存池的框架都会重载operator new目的是从内存池中为类分配内存而不是从系统中。
重载 operator new形式

void * operator new(size_t size);

operator new可以显式调用,也可以通过new来调用,new来调用应该申请内存部分交给operator new,

palcement new是返回内存地址,且在上面调用构造函数,将对象绑定到指定的内存地址
重载palcement new形式:

void * operator new(size_t, void *location)

{

  return location;

}

void *buffer =                      // 分配足够的

  operator new(50*sizeof(char));      // 内存以容纳50char

                                 //没有调用构造函数

...

operator delete(buffer);              // 释放内存

                                 // 没有调用析构函数


Operator delete用来释放内存,它被这样声明:

void operator delete(void *memoryToBeDeallocated);

placement delete一般显式调用类的析构就可以了,实现自己的placement delete也可以。

// 浅析测试代码

int m_nWritePos = 0;

unsigned char g_arrayBuffer[1000]={0};

void * operator new(size_t size)

{

 if(m_nWritePos + size > 1000)

 {

  return g_arrayBuffer + m_nWritePos;

 }

 else

 {

  m_nWritePos += size;

  return g_arrayBuffer + m_nWritePos;

 }

}

void operator delete(void *pNum)

{

 //if(m_nWritePos + size > 1000)

 //{

 // //return g_arrayBuffer + m_nWritePos;

 // m_nWritePos -= (m_nWritePos + size - 1000);

 //}

 //else

 //{

 // m_nWritePos -= size;

 // //return g_arrayBuffer + m_nWritePos;

 //}

 m_nWritePos -= 10;

}

void * operator new(size_t size, void *pLocation)

{

 return pLocation;

}

//void * operator delete(size_t size, void *pLocation)

//{

// return pLocation;

//}

int main()  

{  

 int *pNum = /*new int*/(int*)operator new(10);// 如果直接new int(10) 则operator new(10)也会得到调用

 delete pNum;// 调用析构函数,释放内存空间

 int *pNum2 = (int*)operator new(10, pNum);// new(10, pNum) 只是返回对象的指针,所以分配内存的placement new没有得到调用

}

使用实例:

分配和释放内存:

// Node memory management
	Node *AllocateNode()
	{

#if !USE_FSA_MEMORY
		Node *p = new Node;
		return p;
#else
        // 从内存池中获取一个对象,也可以重载operator new (size_t size)实现内存分配。
		Node *address = m_FixedSizeAllocator.alloc();

		if( !address )
		{
			return NULL;
		}
		m_AllocateNodeCount ++;
        // 用placement new简单的返回地址address,主要的是前后的new Node达到调用构造函数目的,实现对象和地址绑定
		Node *p = new (address) Node;
		return p;
#endif
	}

	void FreeNode( Node *node )
	{

		m_AllocateNodeCount --;

#if !USE_FSA_MEMORY
		delete node;
#else
        // 手动调用析构函数,因为operator delete(size_t size)等形式的只是new出错才调用,否则不能手动调用
		node->~Node();
		m_FixedSizeAllocator.free( node ); // 回收对象到内存池中
#endif
	}
内存池构建:

#include <string.h>
#include <stdio.h>

template <class USER_TYPE> class FixedSizeAllocator
{
    
public:
    // Constants
    enum
    {
        FSA_DEFAULT_SIZE = 100
    };
    
    // This class enables us to transparently manage the extra data
    // needed to enable the user class to form part of the double-linked
    // list class
    struct FSA_ELEMENT
    {
        USER_TYPE UserType;
        
        FSA_ELEMENT *pPrev;
        FSA_ELEMENT *pNext;
    };
    
public: // methods
    FixedSizeAllocator( unsigned int MaxElements = FSA_DEFAULT_SIZE ) :
    m_pFirstUsed( NULL ),
    m_MaxElements( MaxElements )
    {
        // Allocate enough memory for the maximum number of elements
        
        char *pMem = new char[ m_MaxElements * sizeof(FSA_ELEMENT) ];
        
        m_pMemory = (FSA_ELEMENT *) pMem;
        
        // Set the free list first pointer
        m_pFirstFree = m_pMemory;
        
        // Clear the memory
        memset( m_pMemory, 0, sizeof( FSA_ELEMENT ) * m_MaxElements );
        
        // Point at first element
        FSA_ELEMENT *pElement = m_pFirstFree;
        
        // Set the double linked free list
        for( unsigned int i=0; i<m_MaxElements; i++ )
        {
            pElement->pPrev = pElement-1;
            pElement->pNext = pElement+1;
            
            pElement++;
        }
        
        // first element should have a null prev
        m_pFirstFree->pPrev = NULL;
        // last element should have a null next
        (pElement-1)->pNext = NULL;
        
    }
    
    
    ~FixedSizeAllocator()
    {
        // Free up the memory
        delete [] (char *) m_pMemory;
    }
    
    // Allocate a new USER_TYPE and return a pointer to it
    USER_TYPE *alloc()
    {
        
        FSA_ELEMENT *pNewNode = NULL;
        
        if( !m_pFirstFree )
        {
            return NULL;
        }
        else
        {
            pNewNode = m_pFirstFree;
            m_pFirstFree = pNewNode->pNext;
            
            // if the new node points to another free node then
            // change that nodes prev free pointer...
            if( pNewNode->pNext )
            {
                pNewNode->pNext->pPrev = NULL;
            }
            
            // node is now on the used list
            
            pNewNode->pPrev = NULL; // the allocated node is always first in the list
            
            if( m_pFirstUsed == NULL )
            {
                pNewNode->pNext = NULL; // no other nodes
            }
            else
            {
                m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list
                pNewNode->pNext = m_pFirstUsed;
            }
            
            m_pFirstUsed = pNewNode;
        }
        
        return reinterpret_cast<USER_TYPE*>(pNewNode);
    }
    
    // Free the given user type
    // For efficiency I don't check whether the user_data is a valid
    // pointer that was allocated. I may add some debug only checking
    // (To add the debug check you'd need to make sure the pointer is in
    // the m_pMemory area and is pointing at the start of a node)
    void free( USER_TYPE *user_data )
    {
        FSA_ELEMENT *pNode = reinterpret_cast<FSA_ELEMENT*>(user_data);
        
        // manage used list, remove this node from it
        if( pNode->pPrev )
        {
            pNode->pPrev->pNext = pNode->pNext;
        }
        else
        {
            // this handles the case that we delete the first node in the used list
            m_pFirstUsed = pNode->pNext;
        }
        
        if( pNode->pNext )
        {
            pNode->pNext->pPrev = pNode->pPrev;
        }
        
        // add to free list
        if( m_pFirstFree == NULL )
        {
            // free list was empty
            m_pFirstFree = pNode;
            pNode->pPrev = NULL;
            pNode->pNext = NULL;
        }
        else
        {
            // Add this node at the start of the free list
            m_pFirstFree->pPrev = pNode;
            pNode->pNext = m_pFirstFree;
            m_pFirstFree = pNode;
        }
        
    }
    
    // For debugging this displays both lists (using the prev/next list pointers)
    void Debug()
    {
        printf( "free list " );
        
        FSA_ELEMENT *p = m_pFirstFree;
        while( p )
        {
            printf( "%x!%x ", p->pPrev, p->pNext );
            p = p->pNext;
        }
        printf( "\n" );
        
        printf( "used list " );
        
        p = m_pFirstUsed;
        while( p )
        {
            printf( "%x!%x ", p->pPrev, p->pNext );
            p = p->pNext;
        }
        printf( "\n" );
    }
    
    // Iterators
    
    USER_TYPE *GetFirst()
    {
        return reinterpret_cast<USER_TYPE *>(m_pFirstUsed);
    }
    
    USER_TYPE *GetNext( USER_TYPE *node )
    {
        return reinterpret_cast<USER_TYPE *>
        (
         (reinterpret_cast<FSA_ELEMENT *>(node))->pNext
         );
    }
    
public: // data
    
private: // methods
    
private: // data
    
    FSA_ELEMENT *m_pFirstFree;
    FSA_ELEMENT *m_pFirstUsed;
    unsigned int m_MaxElements;
    FSA_ELEMENT *m_pMemory;
    
};




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值