zoukankan      html  css  js  c++  java
  • 关于new你应当知道的一切

         new在C++中是一个我们经常用到的运算符。由它所创建的变量会被分配在堆中,并且在程序结束之前应当将分配的内存delete掉,否则就会导致内存泄漏。但是除此之外,你对new有更深入的了解吗?本篇文章将深入探讨C++中的new运算符,我在这篇文章中总结了new的以下知识点:

         1. new内存分配失败后的处理

         如果你认为new分配失败后应当如以下代码处理:

    int*p=new int;
    if(!p)
    {
        //error processing
    }
    

      那么你就大错特错了。C++中规定当new分配失败时,它会抛出一个bad_alloc exception,此时应当采用异常处理的方法:

    try
    {
          int* pStr=new string[SIZE];
    }
    catch(const bad_alloc& e)
    {
         //error processing  
    }
    

      2. new的三种形态。

         new实际上有三种形态:new operator、operator new和placement new。

         new operator是我们最常用的形态(用法如上文的代码所示),它是语言内建的,不能重载,也不能改变其行为。它在执行过程中,与其余的两种形态都发生了密切的关系:第一步通过operator new来实现内存申请,第二步通过placement new来调用构造函数。

         operator new在默认情况下为调用分配内存的代码,尝试从堆上得到一段空间,如果分配成功则直接返回,分配失败则调用new_handler函数,然后继续重复前面的过程,直到抛出了异常为止。如下的代码便重载了A的operator new函数:

    class A
    {
    public:
        A(int a);
        ~A();
        void* operator new(size_t size);  
    }
    
    void* A::operator new(size_t size)
    {
        cout<<"A's operator new"<<endl;
        return ::operator new(size);
    }
    

      这里调用了全局的new来进行内存分配。

         placement new则是决定在分配的空间里采用哪种构造函数。通常情况下,构造函数是由编译器自动调用的,但你也可以手动调用构造函数。如以下代码所示:

    #include <iostream>
    class X
    {
    public:
    	X() { std::cout << "constructor of X" << std::endl; }
    	~X() { std::cout << "destructor of X" << std::endl; }
    
    	void SetNum(int n)
    	{
    		num = n;
    	}
    
    	int GetNum()
    	{
    		return num;
    	}
    
    private:
    	int num;
    };
    
    int main()
    {
    	char* buf = new char[sizeof(X)];
    	X *px = new(buf)X;
    	px->SetNum(10);
    	std::cout << px->GetNum() << std::endl;
    	px->~X();
    	delete[]buf;
    
    	return 0;
    }

      当然,如果显示地调用placement new,那么也得显示地调用对应的placement delete。

         placement new的意义在于,operator new开辟内存是比较花费时间的,因此你可以一次用operator new开辟一片内存,然后利用placement new重复地在这片内存上构建对象,这样可以省去很多时间。

    3. new_handler函数

        在使用operator new申请内存失败之后, 编译器会调用new_handler函数来进行相应的处理。你可以定制属于自己的new_handler函数,只需要调用<new>中的set_new_handler之中即可,set_new_handler的参数为一个函数指针,返回值为指向的是set_new_handler调用之前的异常处理函数。

       我们也可以根据类设定不同的new_handler函数,以下是一个例子:

       

    class A
    {
    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);
        static void MemoryErrorHandling(); // new_handler function
    private:
        static std::new_handler m_curHandler; 
    };
    std::new_handler A::m_curHandler=NULL;
    std::new_handler A::set_new_handler(std::new_handler p)throw()
    {
        std::new_handler old_handler=m_curHandler;
        m_curHandler=p;
        return old_handler;
    }
    
    void MemoryErrorHandling()
    {
        //...
    }
    
    void *operator new (std::size_t size)throw(std::bad_alloc)
    {
        set_new_handler(MemoryErrorHandling);
        return ::operator new(size);
    }
    

      

  • 相关阅读:
    BestCoder6 1002 Goffi and Squary Partition(hdu 4982) 解题报告
    codeforces 31C Schedule 解题报告
    codeforces 462C Appleman and Toastman 解题报告
    codeforces 460C. Present 解题报告
    BestCoder3 1002 BestCoder Sequence(hdu 4908) 解题报告
    BestCoder3 1001 Task schedule(hdu 4907) 解题报告
    poj 1195 Mobile phones 解题报告
    二维树状数组 探索进行中
    codeforces 460B Little Dima and Equation 解题报告
    通过Sql语句控制SQLite数据库增删改查
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/6735416.html
Copyright © 2011-2022 走看看