zoukankan      html  css  js  c++  java
  • c++中new的用法

    new operator

      内置的new操作符,经常使用的T *ptr = new T(),分配内存,调用构造函数

    1. 调用operator new分配内存,operator new (sizeof(A)) 
    2. 调用构造函数生成类对象,A::A() ,调用placement new
    3. 返回相应指针 

      事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),否则调用全局::operator new(size_t ),后者由C++默认提供。

    operator new

      像普通运算符一样可以被重载,operator new会去申请内存,申请失败的时候会调用new_handler处理,这是一个循环的过程,如果new_handler不抛出异常,会一直循环申请内存,直到成功。

    (1) void* operator new (std::size_t size);
    (2) void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
    (3) void* operator new (std::size_t size, void* ptr) noexcept;
    1. 分配size字节的存储空间,如果成功的话返回一个非空指针,将对象类型进行内存对齐,指向分配空间第一个字节。如果失败的话,会抛出bad_alloc异常,不调用构造函数
    2. 和第一种一样,差别在于,如果失败的话,不抛出异常,而是返回一个null指针,不调用构造函数
    3. 只是返回ptr指针,并不分配内存空间。这里的ptr应该指向先前已经分配好的空间,这里的new调用对象的构造函数,在ptr指向的内存空间构造对象或对象数组。ptr指向的内存只要不释放,可以重复使用,所以这种用法一般在对象池或内存池实现中使用也就是placement new版本
    #include <iostream>
    #include <new>
    using namespace std;
    
    struct A
    {
        A( bool xpt )
        {
            if( xpt )
                throw( xpt );
        }
    
        void *operator new(size_t size)
        {
            cout<<"operator new"<<endl;
            return malloc(size);
        }
        void operator delete(void *p)
        {
            cout<<"operator delete"<<endl;
            free(p);
        }
      
    
        void *operator new(size_t size,const nothrow_t &thorw_value) noexcept
        {
            cout<<"operator new noexcept"<<endl;
            return malloc(size);
        }
        void operator delete(void *p,const nothrow_t &nowthrow_value) throw()
        {
            cout<<"operator delete noexpect."<<endl;
            free(p);
        }
    };
    
    int main()
    {
        A* a1 = new A(false);
        delete a1;
    
        try 
        {    
            A* a2 = new A(true);
            delete a2;
        }
        catch( ... )
        {
            // 
        }
      
    
        A* a3 = new(nothrow) A(false);
        delete a3;
    
        try 
        {
            A* a4 = new(nothrow) A(true);
            delete a4;
        }
        catch( ... )
        {
            
        }
        return 0;
    }

    在分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,因此通过判断返回值是否为NULL是徒劳的。

    placement new

      除了应该有的size_t size参数,多其他的任何参数都可以看做placement new

    1. 这种new允许在一块已经分配成功的内存上重新构造对象或对象数组。placement new不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数
    2. 用定位放置new操作,既可以在栈(stack)上生成对象,也可以在堆(heap)上生成对象。
    3. 使用语句A* p=new (mem) A;定位生成对象时,指针p和数组名mem指向同一片存储区。 会自动调用类A的构造函数,但是由于对象的空间不会自动释放(对象实际上是借用别人的空间),所以必须显示的调用类的析构函数,如本例中的p->~A()。 
    void* operator new (std::size_t size, void* ptr) noexcept;

      placement new构造起来的对象或其数组,要显示的调用他们的析构函数来销毁,千万不要使用delete ,要显式调用它们的析构函数来销毁(析构函数并不释放对象的内存,这是因为placement new构造起来的对象或数组大小并不一定等于原来分配的内存大小,使用delete会造成内存泄漏或者之后释放内存时出现运行时错误。

    #include <iostream>
    #include <new>
    #include <cstdio>
    using namespace std;
    
    struct A
    {
        char c;
        int i;
        short a;
    }; 
    
    int main()
    {
        A *a1=new A;
        A *a2=new(a1) A;//再堆上构造对象
        
        char *c={"fdsafk"};//在栈上构造对象 
        cout<<(void *)c<<endl;
        
        A *a3=new(c) A;
        cout<<a3<<endl;
        return 0;
    }

      当使用new运算符定义一个多维数组变量或数组对象时,它产生一个指向数组第一个元素的指针,返回的类型保持了除最左边维数外的所有维数。例如:  

     int *p1 = new int[10];   

      返回的是一个指向int的指针int*  

    int (*p2)[10] = new int[2][10]; 

      new了一个二维数组, 去掉最左边那一维[2], 剩下int[10], 所以返回的是一个指向int[10]这种一维数组的指针int (*)[10].  

      int (*p3)[2][10] = new int[5][2][10];  new了一个三维数组, 去掉最左边那一维[5], 还有int[2][10], 所以返回的是一个指向二维数组int[2][10]这种类型的指针int (*)[2][10].     

    #include<iostream>
    #include <typeinfo> 
    using namespace std;
    
    int main() 
    { 
        int *a = new int[34]; 
        int *b = new int[]; 
        int (*c)[2]=new int[][2];//指针 
        
        int[34][2]; 
        int (*d)[2] = new int[][2]; //指针 
        int (*e)[2][3] = new int[34][2][3];
        int (*f)[2][3] = new int[][2][3];//指针 
        
        a[0] = 1; 
        b[0] = 1; //运行时错误,无分配的内存,b只起指针的作用,用来指向相应的数据
        c[0][0] = 1;
        d[0][0] = 1;//运行时错误,无分配的内存,d只起指针的作用,用来指向相应的数据 
        e[0][0][0] = 1; 
        f[0][0][0] = 1;//运行时错误,无分配的内存,f只起指针的作用,用来指向相应的数据 
    
        cout<<typeid(a).name()<<endl;
        cout<<typeid(b).name()<<endl;
        cout<<typeid(c).name()<<endl; 
        cout<<typeid(d).name()<<endl; 
        cout<<typeid(e).name()<<endl;
        cout<<typeid(f).name()<<endl; 
        delete[] a; 
        delete[] b; 
        delete[] c; 
        delete[] d; 
        delete[] e; 
        delete[] f; 
        return 0;
    }   
     

     

  • 相关阅读:
    笔记35 跨重定向请求传递数
    判断邮箱的正则表达式
    按钮
    async await 的用法
    笔记34 Spring MVC的高级技术——处理multipart形式的数据
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Unique Binary Search Trees,Unique Binary Search Trees II
    Validate Binary Search Tree
    Populating Next Right Pointers in Each Node,Populating Next Right Pointers in Each Node II
  • 原文地址:https://www.cnblogs.com/tianzeng/p/8964215.html
Copyright © 2011-2022 走看看