C++的malloc和new的区别

1.对于C++而言,malloc是函数,但是new是运算符

看似函数和运算符实现的功能都差不多。但是对于C++来说,new是运算符就意味着我们可以进行运算符重载,这就意味着我们可以定制我们自己的new内存分配器。
同时,由于C++特有的异常处理机制,我们不但可以在我们内存分配失败的时候,new返回一个null,同时也可以报出一个bad_alloc错误,同时调用我们的new_handler(new运算符错误处理程序),但是我们的new_handler应该如何写呢。
还是先来一段代码:

class NewHandlerHolder
{
public:
    explicit NewHandlerHolder(std::new_handler nh):handler(nh)  //取得目前的new-handler.释放它
    ~NewHandlerHolder()
    {std::set_new_handler(handler); }
private:
    std::new_handler handler;           //记录下来,阻止copying
    NewHandlerHolder(const NewHandlerHolder&);  
    NewHandlerHolder& operator=(const NewHandlerHolder&);
};

void* Widget::operator new(std::size_t size) throw(std::bad_alloc)
{
    NewHandlerHolder h(std::set_new_handler(currentHandler));   //安装Widget的new-handler.
    return ::operator new(size);                    //分配内存或抛出异常.恢复global new-handler.
}

template<typename T>    //"mixin"风格的base class,用以支持
//class 专属的set_new_handler
class NewHandlerSupport
{
public:
    static std::new_handler set_new_handler(std::new_handler p)throw();
    static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
    static std::new_handler currentHandler;
};

template<typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw()
{
    std::new_handler oldHandler=currentHandler;
    currentHandler=p;
    return oldHandler;
}
template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
    NewHandlerHolder h(std::set_new_handler(currentHandler));
    return ::operator new(size);
}
//以下将每一个currentHandler初始化为null
template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler=0;

上面的代码,将我们重载的New以及new_handler函数封装成了一个类使用。但是,这里要注意的是,如果我们多重继承这个NewHandler类,要看适不适合我们的类,否则将会出现错误。

2.对于C++而言,new运算符可以动态申请我们的一个对象的空间

这里,我还是以一个例子来说明new来动态申请我们的一个对象的空间会引发什么问题:

Example* em=new Example

我们申请一个Example类的对象的时候,一共做了两件事:
1.类似malloc的过程申请了一块空间。
2.调用Example类的构造函数。
但是如果在第二步的时候,程序抛出了异常。那么是不是代表着new的过程失败了,抛出一异常,返回了null。第一步申请的空间还是申请,但没有得到指针进行delete操作,这就造成了内存泄露。
这明显是我们不想看到的不可控的情况。
实际上解决这个问题的方法也有两种:
1.对内存块进行签名。
2.我们每一次new的过程中都要返回一个指向空间的指针就行了。
实际上,我们的C++的new库已经为我们实现了这个功能:

#include<new>
void* operator new(std::size_t,void* pMemory) throw()

那个pMemory就是指向我们空间的指针啦,这样即使出现刚刚的情况,我们也可以利用这个指针来进行返回。
还有一种是基于签名的方式,这里还是直接上代码:

static const int signature=0xDEADBEEF;
typedef unsigned char Byte;
void* operator new(std::size_t size) throw(std::bad_alloc)
{
    using namespace std;
    size_t realSize=size+2*sizeof(int);     //增加大小,使能够塞入两个signatures.
    void* pMem=malloc(realSize);            //调用malloc取得内存。
    if(!pMem) throw bad_alloc();

    //将signature写入内存的最前段落和最后段落
    //减一个int是为了能够写在这个int的地方写上签名
    *(static_case<int*>(pMem))=signature;
    *(reinterpret_case<int*>(static_case<Byte*>(pMem)+realSize-sizeof(int)))=signature;

    //返回指针,指向恰位于第一个signature之后的内存位置.
    return static_cast<Byte*>(pMem)+sizeof(int);
}

可以从代码看出,主要做的改动就是把原来申请的空间扩展了两个int的签名,然后头尾加上签名,之后返回的是第一个签名后的内存位置。
但是这样做可能无法实现的内存对齐的要求(内存对齐是为了更快的访问(直接通过内存的移位操作进行访问))。
既然提到了内存对齐的问题,这里就要提一下一个优秀的内存分配器应该考虑什么,我们考虑个性化的内存分配器应该考虑什么?

3.优秀的内存分配器应该如何设计考虑

内存分配器的具体设计在我的另一篇博客上有提到:
http://blog.csdn.net/github_33873969/article/details/78571868
这里我们更专注内存分配器的其他方面:
1.线程安全(在多线程环境下,我们的new过程还是否安全)
2.文件系统的内存对齐问题
3.对于使用内存情况的统计问题
4.为了将相关对象成簇集中
这里我们简单的提几点
1.为了保证线程安全的时候,我们在new的时候如果对链表进行操作需要对链表的结点利用锁机制进行保护。但是这样就会降低一定量的效果。这就给我们定制new做了一个要求,要在只有单线程的环境下把相关锁关掉。
3.关于使用内存情况的统计问题,我们可以在我们的new的过程中,统计我们申请的块的大小情况,回收与申请的时间间隔如何,他们更倾向于FIFO次序或LIFO(后进先出)次序,之后我们可以再进行合理化定制。
4.为了将相关对象成簇集中。为了考虑局部性原理,我们可以将相同的对象放在一起,为了能够得到cache亲和,来进行快速访问。
Reference:Effective C++ (改善程序与设计的55个具体做法)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++mallocnew都可以用来动态分配内存。但是它们有一些不同之处。使用new操作符分配内存是类型安全的,而malloc函数则不是。\[1\]当使用new分配内存失败时,会抛出bad_alloc异常,而malloc分配内存失败时会返回null指针。\[1\]另外,C++保留了malloc/free的功能是为了兼容性考虑,因为C++程序可能需要调用C函数,而C语言只能使用malloc/free来管理内存。\[2\]malloc函数是C语言的一个函数,它在堆区申请一块指定大小的内存空间,由开发者自己管理这块内存空间。\[3\]相比之下,new操作符更加方便和安全,因为它会自动调用构造函数来初始化对象,并且在对象不再使用时会自动调用析构函数来释放内存。 #### 引用[.reference_title] - *1* [C++ newmalloc区别](https://blog.csdn.net/ymhdt/article/details/125991187)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++ newmalloc区别](https://blog.csdn.net/weixin_50697073/article/details/122951910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C/C++ mallocnew](https://blog.csdn.net/m0_53184209/article/details/128000317)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值