• c++ 关于new文件


    new文件用来管理c++的动态内存,这个文件声明了几个全局空间的函数(不是std空间的函数,全局空间的函数调用时是用全局作用域解析符),包括operator new 和operator delete的重载 ,这些函数用于处理动态存储空间请求。

    其new的头文件源代码

    #ifndef _NEW
    #define _NEW
    
    #include <cstddef>
    #include <exception>
    
    extern "C++" {
    
    namespace std 
    {
      
      //注意此空间内函数或者变量处于std空间,使用时需要添加std::调用
      /**
       *  当内存分配错误的时候抛出bad_alloc异常
       */
      class bad_alloc : public exception 
      {
      public:
        bad_alloc() throw() { }
        virtual ~bad_alloc() throw();
      };
    
      //当内存分配失败时用此结构体替代异常,使用嵌入式环境,嵌入式环境没有异常功能
      struct nothrow_t { };
      extern const nothrow_t nothrow;
    
      ///当内存分配失败时,调用new_handler
      ///new_handler试着去分配更多得存储空间,当且仅当申请内存成功时,才会返
      ///否则抛出bad_alloc异常或者终止程序(调用abort或者exit)
      typedef void (*new_handler)();
      new_handler set_new_handler(new_handler) throw();
    } // namespace std
    
    //全局空间函数,调用时加上作用域解析符,如::operator new ()
    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();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();
    
    //placement operator new/delete
    
    inline void* operator new(std::size_t, void* __p) throw() { return __p; }
    inline void* operator new[](std::size_t, void* __p) throw() { return __p; }
    
    
    inline void  operator delete  (void*, void*) throw() { }
    inline void  operator delete[](void*, void*) throw() { }
    
    } // extern "C++"
    
    #endif

     1、关于new operator与operator new

         operator new() 仅仅分配内存空间,是对malloc的一个封装,返回的是一个void *,如

    int* a = (int *)::operator new(sizeof(int));

      只是对a分配了空间,通过vs2012进行调试你会发现operator new 的实现如下:其主要是调用malloc(size),而没有对内存进行初始化

    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) {       // try to allocate size bytes
            void *p;
            while ((p = malloc(size)) == 0)
                    if (_callnewh(size) == 0)
                    {       // report no memory
                    static const std::bad_alloc nomem;
                    _RAISE(nomem);
                    }
    
            return (p);
      }

      对于new operator先调用operator new分配内存空间,然后调用构造函数初始化

    #include <iostream>
    using namespace std;
    
    class Foo{
    public:
        Foo(){
            cout<<"Foo constructor"<<endl;
            a = 10;
        }
    
        //对operator new进行重写
        void* operator new(size_t size){
            cout<<"Foo operator new"<<endl;
            return ::operator new(size);
        }
    
        int a;
    };
    
    int main(){
        Foo* f1 =(Foo *) ::operator new(sizeof(Foo));
        cout<<f1->a<<endl;
        Foo* f2 = new Foo();
        cout<<f2->a<<endl;
    }
    
    /***************
     结果为:
     3420040
     Foo operator new
     Foo constructor
     10
     
     *****************/

    由于operator new 只是分配空间未调用构造函数,所以公有变量未初始化,是个随机值,

    而new Foo() 先调用operator new 然后再构造函数,所以会先出现Foo operator new

    2、关于placement new(定位放置new)

    placement new 是operator new的一个重载的版本,如果你想在已经分配的内存中创建一个对象,这时不能使用new。而placement new永许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象,原型中void* p实际就是指向一个已经分配好的内存缓冲区的首地址。c++支持placement operator new,能够在预先分配的缓冲区中构造对象,避免new内存分配时查找内存和分配内存的时间,而且由于内存已经分配,没有内存分配失败的危险,在内存池,垃圾回收器,和性能或异常安全可以使用

    char *buf  = new char[sizeof(string)]; // pre-allocated buffer
    string *p = new (buf) string("hi");    // placement new
      char memory[sizeof(Foo)];     
      void* place = memory;         
    
      Foo* f = new(place) Foo(); 

     3、关于set_new_handler

     new_handler类型的函数是默认内存申请函数(operator new和operator new[])申请内存失败,会被调用。

     new_handler函数会试图为新的内存申请请求提供更多的可用空间。当且仅当,函数成功地提供了更多的可用空间,它才返回。

    否则,要么抛出bad_alloc异常(或bad_alloc派生类)要么终止程序(比如调用abort或exit)。

     如果new_handler函数返回(即,它提供了更多可用空间)后,当内存申请函数申请指定的内存空间失败时,它会被再次调用,或直到new_handle函数不返回或被替换。

    #include <iostream>
    #include <new>
    
    char* memoryPool = NULL;
    
    void my_new_handler(){
        if(NULL != memoryPool){
            // 删除一些不用的内存
            delete[] memoryPool;
            memoryPool = NULL;
        }else{
            //没有足够的内存
            throw std::bad_alloc();
        }
        return ;
    }
    
    int main(){
        std::set_new_handler(my_new_handler);
        memoryPool = new char[512*1024*1024];
        if(memoryPool == NULL){
            std::cout<<"allocator fail"<<std::endl;
            return -1;
        }
        char *p = NULL;
        for(int i = 0 ; i < 4; ++ i){
            p = new char[256*1024*1024];
            std::cout<<i+1<<" allocator 512M  "<<p<<std::endl;
        }
        return 0;
    }
  • 相关阅读:
    23种设计模式-桥接模式
    23种设计模式-单列模式
    23种设计模式-迭代器模式
    23种设计模式-组合模式
    23种设计模式-备忘录模式
    23种设计模式-适配器模式
    23种设计模式-状态模式
    SVN的安装和应用
    线程、线程池
    条形码
  • 原文地址:https://www.cnblogs.com/xiongqiangcs/p/3737545.html
Copyright © 2020-2023  润新知