zoukankan      html  css  js  c++  java
  • c++ new, operator new, placement new

    c++ new 用于动态分配内存。比如 A* a=new A();其实这里一共有三步:

    1、分配sizeof(A)的内存,这里的分配是通过operator new(std::size_t)实现的

    2、在分配的内存上初始化,调用A的构造函数

    3、返回相应指针

    某些时候我们需要重载operator new来达到一些目的,如内存泄漏检查。

    一、operator new重载

    需要注意几个问题:

    1、应该实现handle_new,即分配内存不成功时的措施。

    2、第一个参数应该是std::size_t

    3、一般不重载placement new,placement new本身就是operator new的一种标准重载形式

    4、重载operator new后要实现相应的operator delete,不过只有分配内存失败时才会调用重载的delete,或者还是会调用全局delete

    重载实例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class X
    {
    public:
        X() { cout<<"constructor of X"<<endl; }
        ~X() { cout<<"destructor of X"<<endl;}
    
        void* operator new(size_t size,string str)
        {
            cout<<"operator new size "<<size<<" with string "<<str<<endl;
            return ::operator new(size);
        }
    
        void operator delete(void* pointee)
        {
            cout<<"operator delete"<<endl;
            ::operator delete(pointee);
        }
    private:
        int num;
    };
    
    int main()
    {
        X *px = new("A new class") X;
        delete px;
    
        return 0;
    }

    二、placement new

    placement new可以在指定的内存空间上构造对象,它的原型为:

    void * operator new(std::size_t,void *p){
            return p;
    }

    使用方式如下:

    new(ptr) A();其中ptr为已分配好的内存。

    Placement new使用步骤

    在很多情况下,placement new的使用方法和其他普通的new有所不同。这里提供了它的使用步骤。

    第一步  缓存提前分配

    有三种方式:

    1.为了保证通过placement new使用的缓存区的memory alignment(内存队列)正确准备,使用普通的new来分配它:在堆上进行分配
    class Task ;
    char * buff = new [sizeof(Task)]; //分配内存
    (请注意auto或者static内存并非都正确地为每一个对象类型排列,所以,你将不能以placement new使用它们。)

    2.在栈上进行分配
    class Task ;
    char buf[N*sizeof(Task)]; //分配内存

    3.还有一种方式,就是直接通过地址来使用。(必须是有意义的地址)
    void* buf = reinterpret_cast<void*> (0xF00F);

    第二步:对象的分配

    在刚才已分配的缓存区调用placement new来构造一个对象。
    Task *ptask = new (buf) Task

    第三步:使用

    按照普通方式使用分配的对象:

    ptask->memberfunction();

    ptask-> member;

    //...

    第四步:对象的析构

    一旦你使用完这个对象,你必须调用它的析构函数来毁灭它。按照下面的方式调用析构函数:
    ptask->~Task(); //调用外在的析构函数

    第五步:释放

    你可以反复利用缓存并给它分配一个新的对象(重复步骤2,3,4)如果你不打算再次使用这个缓存,你可以象这样释放它:delete [] buf;

    三、operator new[]

    new[]和new类似,仍然会优先调用类中重载的operator new[]。另外还要注意的是,在operator new[](size_t size)中传入的并不是sizeof(A)*num。而要在对象数组的大小上加上一个额外数据,用于编译器区分对象数组指针和对象指针以及对象数组大小

  • 相关阅读:
    第二阶段--个人冲刺--第七天
    学习进度条12
    第二阶段--个人冲刺--第六天
    第二阶段--个人冲刺--第五天
    第二阶段--个人冲刺--第四天
    第二阶段--个人冲刺--第三天
    从小工到专家阅读笔记03
    团队冲刺第一阶段第十天
    团队冲刺第一阶段第九天
    构建之法阅读笔记05
  • 原文地址:https://www.cnblogs.com/coderht/p/7206283.html
Copyright © 2011-2022 走看看