处理从CTOR抛出的异常?

时间:2014-03-12 19:50:25

标签: c++ exception constructor

TL;博士

我想做这样的事情:

foo()
{
  Y* p;
  try {
    p = new Y();
  } catch {
    //fix any problem that may have occured
  }
  // Now I know the object was fixed during catch or simply was created successfully.
  p.do_something();
  // win
}

我正在创建的对象是使用有时不可靠的永恒资源。在没有必要的预防措施的情况下尝试分配是危险的。如果确实失败了,那么有些事情可以做。然而,似乎抛出一个异常,不像我后来展示的switch语句,不允许我修复AFAIK的问题。

我被建议从构造函数中抛出异常。但是,我不明白这是如何有用的,因为我不知道如何处理这个例外?我进行了搜索并找到了this example,但我不确定它是否真的是一种有用的可扩展方法来处理施工失败。

示例代码:

void f()
{
  X x;             //← if X::X() throws, the memory for x itself will not leak
  Y* p = new Y();  //← if Y::Y() throws, the memory for *p itself will not leak
}

让我们说堆上有更多的实例在p之前分配。他们不会因此而泄漏到记忆中吗?因此函数f仅用于构造Y的实例。移动危险的"是不是总是更有用?建筑外面的另一种方法?

我通常做的事情:

X* x = new X(); //No dangerous operation

switch (x.init()) // init returns int
  {
    case ...
    // Handle failed init() here
  }

这有缺点吗?它似乎更可靠。

3 个答案:

答案 0 :(得分:2)

您应该在每个成员上使用RAII(资源获取是初始化)。只有在构造函数完成时才会调用对象的析构函数。这样,如果只调用两个成员的构造函数中的一个,则只调用该成员的析构函数,其中应执行任何清理。

class Locked_file_handle {
    File_ptr p;
    unique_lock<mutex> lck;
public:
    X(const char* file, mutex& m)
        :p{file, "rw"},
        lck{m} 
    {}
    // ..
};

如果在构造p之后但在lck之前发生了异常,那么将调用p而不是lck的析构函数。这样做会让构造函数的作者放弃编写显式异常处理代码。

来源:“C ++编程语言第4版”(Stroustrup)

编辑:所以在你的情况下,它看起来像这样

public class YHandle {
    Y* p;
    YHandle() {
        Y = new Y()
    }
    ~YHandle() {
        delete Y;
    }
}

foo() {
    YHandle p = YHandle();
    p.do_something();
} // p is deleted here

答案 1 :(得分:1)

您的示例是安全的,因为如果c&#39; tor抛出异常,则在传递异常之前释放为无法构造的对象分配的内存。当异常退出f范围时,堆栈将被解开。

如果一个半构造且随后具有其成员和基础被破坏的对象被返回到调用范围,则该范围无法确定如何正确释放该内存,因此谢天谢地,这还没有完成。

如果在同一函数的堆上构造其他对象,则通常的规则适用。原则上,你不需要在这里进行特殊情况的调用,只是假装抛出的语句是一个常规的函数调用。

答案 2 :(得分:-1)

如果投掷可能导致泄漏,那么您负责删除分配

你可以像这样滚动例外:

void f()
{
  X x;             //← if X::X() throws, the memory for x itself will not leak
  Y* p;
  try{  
    p = new Y();  //← if Y::Y() throws, the memory for *p itself will not leak
  } catch(exception &e){
    ///clean what you need

    throw e;
  }
}
相关问题