【问题标题】:Behaviour of exception handling in constructor of a class类的构造函数中异常处理的行为
【发布时间】:2014-10-07 06:18:24
【问题描述】:

我有这个程序,派生类的 ctor 抛出异常。该程序只是一个示例程序,我只是想了解异常处理的概念。

class A{
public:
   A() {}

   ~A(){std::cout << "DTOR called - A!!" << std::endl;}
};

class B : public A
{
public:
   B():A()
   {
      try
      {
         init();
      }
      catch(...)
      {
         std::cout << "Inside catch block in B's Ctor!!" << std::endl;
         throw this;
      }
   }

   void init() { throw 0;  }

   ~B() {std::cout << "DTOR called - B!!" << std::endl; }
};

int main()
{
   try{
      B *b = new B;

      std::cout << "Äfter B's ctor called in try block!!" << std::endl;
      delete b;
      std::cout << "Äfter B's dtor called in try block!!" << std::endl;
   }

   catch(B* b)
   {
      delete b;
      b = NULL;
      std::cout << "Exception Occurred in B!!" << std::endl;
   }

   catch(A* a)
   {
      delete a;
      a = NULL;
      std::cout << "Exception Occurred in A!!" << std::endl;
   }

   catch(...)
   {
      std::cout << "Exception Occured!!" << std::endl;
   }
   return EXIT_SUCCESS;
}

预期的输出是它应该进入 B 的 catch 块,首先应该调用 B 的 dtor,然后调用 A 的 dtor。但是上面程序的输出是:

Inside catch block in B's Ctor!!
DTOR called - A!!
DTOR called - B!!
DTOR called - A!!
Exception Occurred in B!!

我的问题是为什么A类的dtor只进入B类的catch块并只调用B类的dtor时调用了两次? 另外请告诉我是否在这里犯了一些错误。 任何帮助表示赞赏

编辑:

class B : public A
{
public:
   B():A()
   {
      try
      {
         szName = new char[100];
         init();
      }
      catch(...)
      {
         std::cout << "Inside catch block in B's Ctor!!" << std::endl;
         throw this;
      }
   }

   void init() { throw 0;  }

   ~B()
   {
      delete szName;
      std::cout << "DTOR called - B!!" << std::endl;
   }

   char *szName;
};

在这里,我在 B 类中创建了一个 char 指针。在抛出异常之前,在 Ctor 的 try 块中分配了内存。现在在这种情况下,如果我没有捕获 B 类的异常,是否会出现内存泄漏??

【问题讨论】:

标签: c++ exception-handling


【解决方案1】:

你为什么在你的 catch 块里扔“这个”?你在做“这个”的时候已经吐了,你怎么能扔呢?试着扔掉你抓到的东西,或者其他东西,比如“哎呀”。

【讨论】:

  • 我正在抛出“this”,否则会导致内存泄漏。那你将如何删除分配给“b”的内存呢??
  • 不是问题,除非你在抛出之前已经在构造函数中分配了一些 ELSE。
  • @SaurabhBhola: new 自动释放它分配的内存,如果构造函数抛出。没有必要自己尝试。
【解决方案2】:

不要抛出this:当异常被捕获时,失败的对象已经不存在了。它已经被清理了,析构函数调用了它的成员和基类,并且它的内存被异常处理机制自动释放。尝试再次删除它是错误的。

只要抛出一个普通的异常类型(最好是std::exception的子类型),就像从任何其他函数中一样。

【讨论】:

    【解决方案3】:

    之所以会调用两次~A(),是因为在B()的体内,A()是完全初始化的,所以出现异常时会自动调用~A(),而B()本身则没有尚未完全初始化,因此不会调用~B(),如果构造函数抛出,您不需要也不应该删除指针,在这种情况下,C++ 将为您调用delete。见LIVE DEMO

    【讨论】:

      【解决方案4】:

      1)B *b = 新 B;

      完成A类的建设

      类B的构造不完整

      2) 扔掉这个;

      它会释放A类部分,所以~A()被调用,~B()不被调用,因为它的构造不完整

      3)控制去catch(B* b)

      删除 b;

      先叫~B,然后叫~A

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-08
        • 2011-10-10
        • 2020-12-04
        相关资源
        最近更新 更多