c ++类构造函数中的内存泄漏

时间:2014-07-22 05:44:29

标签: c++ memory memory-management memory-leaks

我有以下课程

class CSample
{
   char* m_pChar;
   double* m_pDouble;

 CSample():m_pChar(new char[1000]), m_pDouble(new Double[1000000])
{
}
~CSample()
{
   if(m_pChar != NULL) delete [] m_pchar;
   if(m_pDouble != NULL) delete [] m_pDouble;
}
};

在我的main()函数中我试图创建CSample的对象

int main()
{
    try
  {
    CSample objSample;
  }

catch(std::bad_alloc)
{
  cout<<"Exception is caught !!! Failed to create object";
}

}

假设在构造函数的初始化列表中为m_pDouble分配内存时,由于可用内存不足,它会抛出异常。但是对于m_pChar它已经被分配了。由于没有创建对象本身,因此不会调用析构函数。然后m_pChar会有内存泄漏。

你如何避免这种内存泄漏?

2 个答案:

答案 0 :(得分:5)

您可以使用vector来轻松避免此类问题。

class CSample
{
   std::vector<char> m_pChar;
   std::vector<double> m_pDouble;

   CSample():m_pChar(1000), m_pDouble(1000000)
   {
   }
};

一般来说,您的目标应该是编写不需要析构函数的类。这使得他们琐碎地服从Rule of Three

答案 1 :(得分:3)

有几种方法可以安全地执行此操作:

  • 将内存管理委派给另一个类,例如std::unique_ptr(C ++ 11)或std::vector

    class CSample
    {
       std::unique_ptr<char []> m_pChar;
       std::unique_ptr<double []> m_pDouble;
    
       CSample():m_pChar(new char[1000]), m_pDouble(new double[1000000])
       {
       }
    };
    

    语言保证如果抛出异常,将会销毁已构造的任何类成员,这将释放分配的内存。

  • 改为在构造函数体中执行内存分配,并使用本地try块:

    class CSample
    {
       char* m_pChar;
       double* m_pDouble;
    
        CSample() : m_pChar(nullptr), m_pDouble(nullptr)
        {    
            try {
                m_pChar = new char[1000];
                m_pDouble = new double[1000000];
            }
            catch(...){
                if(m_pChar) delete [] m_pChar;
                if(m_pDouble) delete [] m_pDouble;
                throw;
            }    
        }
        CSample(const CSample &other) { /* perform deep copy */ }
        CSample &operator=(const CSample &other) { /* perform deep copy of other and release my resources */ }        
        ~CSample()
        {
           if(m_pChar) delete [] m_pchar;
           if(m_pDouble) delete [] m_pDouble;
        }
    
    };
    
  • 使用C ++ 11委托构造函数。当目标(非委托)构造函数完成执行时,该对象被视为构造,因此如果委托构造函数稍后抛出,则将调用析构函数。

    class CSample
    {
        char* m_pChar;
        double* m_pDouble;
    
        CSample(int) : m_pChar(nullptr), m_pDouble(nullptr) { }
        CSample() : CSample(0)
        {    
            m_pChar = new char[1000];
            m_pDouble = new double[1000000];
        }
        CSample(const CSample &other) { /* perform deep copy */ }
        CSample &operator=(const CSample &other) { /* perform deep copy of other and release my resources */ }
        ~CSample()
        {
           if(m_pChar) delete [] m_pchar;
           if(m_pDouble) delete [] m_pDouble;
        }
    
    };
    

如果您没有将资源管理委托给另一个类,则还需要supply proper copy constructors and copy assignment operators,因为默认的(成员复制/赋值)具有错误的语义。显而易见的是,第一种方法既是最简单的,也是最不容易出错的。