如果在构造函数中抛出异常,最好的做法是防止内存泄漏?

如果在构造函数中抛出异常,析构函数将不会被调用(简单类,不继承).因此,如果在构造函数中抛出异常,并且有一些堆内存未被清除的机会.那么这里最好的做法是什么?

如果你避免“裸”资源(如裸指针,裸互斥体等),并将所有内容都包含在具有适当RAII行为的容器或类中,那么即使存在异常,也不会有您所描述的问题.

也就是说,不要在构造函数中获取裸资源.而是创建一个本身跟随RAII的对象的实例.这样,即使您的构造函数失败(即创建实例的构造函数),将调用初始化对象的析构函数.

所以,这是不好的做法:

#include<iostream>
#include<stdexcept>
 
struct Bad {
  Bad() {
    double *x = new double;
    throw(std::runtime_error("the exception was thrown"));
  }
 
  ~Bad() {
    delete x;
    std::cout<<"My destructor was called"<<std::endl;
  }
 
  double *x;  
};
 
int main() {
  try {
    Bad bad;
  } catch (const std::exception &e) {
    std::cout<<"We have a leak! Let's keep going!"<<std::endl;
  }
  std::cout<<"Here I am... with a leak..."<<std::endl;
  return 0;
}

输出:

We have a leak! Let's keep going!
Here I am... with a leak...

一个更正的例子:

#include<iostream>
#include<stdexcept>
 
struct Resource {
 
  Resource() {
    std::cout<<"Resource acquired"<<std::endl;    
  }
 
  ~Resource() {
    std::cout<<"Resource cleaned up"<<std::endl;        
  }
 
};
 
struct Good {
  Good() {
    std::cout<<"Acquiring resource"<<std::endl;
    Resource r;
    throw(std::runtime_error("the exception was thrown"));
  }
 
  ~Good() {
    std::cout<<"My destructor was called"<<std::endl;
  }  
};
 
 
int main() {
  try {
    Good good;
  } catch (const std::exception &e) {
    std::cout<<"We DO NOT have a leak! Let's keep going!"<<std::endl;
  }
  std::cout<<"Here I am... without a leak..."<<std::endl;
  return 0;
}

输出:

Acquiring resource
Resource acquired
Resource cleaned up
We DO NOT have a leak! Let's keep going!
Here I am... without a leak...

我的观点如下:尝试将需要解放的所有资源封装到构造函数不抛出的类中,析构函数正确地释放资源.然后,在析构函数可能抛出的其他类中,只需创建包装资源的实例,并将保证获取的资源包装器的析构函数将被清理.

以下可能是一个更好的例子:

#include<mutex>
#include<iostream>
#include<stdexcept>
 
// a program-wIDe mutex
std::mutex TheMutex;
 
struct Bad {
  Bad() {
    std::cout<<"Attempting to get the mutex"<<std::endl;
    TheMutex.lock();
    std::cout<<"Got it! I'll give it to you in a second..."<<std::endl;
    throw(std::runtime_error("Ooops,I threw!"));
    // will never get here...
    TheMutex.unlock();
    std::cout<<"There you go! I released the mutex!"<<std::endl;    
  }  
};
 
struct ScopedLock {
  ScopedLock(std::mutex& mutex)
      :m_mutex(&mutex) {
    std::cout<<"Attempting to get the mutex"<<std::endl;
    m_mutex->lock();
    std::cout<<"Got it! I'll give it to you in a second..."<<std::endl;    
  }
 
  ~ScopedLock() {
    m_mutex->unlock();
    std::cout<<"There you go! I released the mutex!"<<std::endl;        
  }
  std::mutex* m_mutex;      
};
 
struct Good {
  Good() {
    ScopedLock autorelease(TheMutex);
    throw(std::runtime_error("Ooops,I threw!"));
    // will never get here
  }  
};
 
 
int main() {
  std::cout<<"Create a Good instance"<<std::endl;
  try {
    Good g;
  } catch (const std::exception& e) {
    std::cout<<e.what()<<std::endl;
  }
 
  std::cout<<"Now,let's create a Bad instance"<<std::endl;
  try {
    Bad b;
  } catch (const std::exception& e) {
    std::cout<<e.what()<<std::endl;
  }
 
  std::cout<<"Now,let's create a whatever instance"<<std::endl;
  try {
    Good g;
  } catch (const std::exception& e) {
    std::cout<<e.what()<<std::endl;
  }
 
  std::cout<<"I am here despite the deadlock..."<<std::endl;  
  return 0;
}

输出(用gcc 4.8.1编译,使用-std = c 11):

Create a Good instance
Attempting to get the mutex
Got it! I'll give it to you in a second...
There you go! I released the mutex!
Ooops,I threw!
Now,let's create a Bad instance
Attempting to get the mutex
Got it! I'll give it to you in a second...
Ooops,let's create a whatever instance
Attempting to get the mutex
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值