• 关于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);
    }
    

      

  • 相关阅读:
    2017(秋)软工作业: (2)硬币游戏—— 代码分析与改进
    软工作业(1)课程学习热身
    用户体验分析:以 “师路南通网站” 为例
    用户体验分析: 以 “南通大学教务管理系统微信公众号” 为例
    软件工程第二次作业:硬币游戏—— 代码分析与改进
    自我介绍
    用户体验分析---以师路南通为例
    用户体验分析---七八点照相馆
    硬币游戏—— 代码分析与改进
    About me
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/6735416.html
Copyright © 2020-2023  润新知