抛出具有const引用局部变量的异常

时间:2014-12-06 22:29:30

标签: c++ stack-unwinding

在堆栈展开期间局部变量会发生什么,在异常中引用?请考虑以下代码:

class bar;
class my_error
{
public:
    my_error(const bar& bar) : _bar(bar) {}
    const bar& get_bar() const { return _bar; }

private:
    const bar& _bar;
}


...

bar some_local_object(...);
if (!foo()) {
   throw my_error(some_local_object);
}

...

try {
    g();
} catch (my_error& e) {
    e.get_bar()
    ...
}

some_local_object 会发生什么?在堆栈展开期间是否应该销毁它?使用它是否安全,如示例所示?

其他问题

如前所述,此代码会导致未定义的行为。我的第二个问题是:

如果我既不允许传递对本地对象的引用也不应该尝试复制它,因为在极少数情况下它可能导致bad_alloc(这就是为什么,我猜,gcc标准库没有有意义的错误消息,即map.at抛出what()返回" map.at")的异常,那么传递附加信息的好策略是什么?请注意,即使连接多个字符串,在构造错误消息期间理论上也可能导致bad_alloc。即:

void do_something(const key& k, ....)
{
    ...
    if (!foo(k)) {
        std::ostringstream os;
        os << "Key " << k << " not found"; // could throw bad_alloc
        throw std::runtime_error(os.str()); 
    }
    // another approcach
    if (!foo(k)) {
        throw key_not_found(k); // also bad, because exception could outlive k
    }
}

2 个答案:

答案 0 :(得分:4)

行为与返回对堆栈上的变量的引用时的行为相同:在您使用它之前,对象将被销毁。也就是说,在捕获异常时,引用的对象将被销毁,并且对引用的所有访问都会导致未定义的行为。

标准中的相关条款是15.2 [except.ctor]第1段:

  

当控件从抛出异常的位置传递到处理程序时,将为输入try块后构造的所有自动对象调用析构函数。自动对象按照完成构造的相反顺序销毁。

答案 1 :(得分:3)

在堆栈展开期间销毁本地对象。然后该引用变为无效,悬空引用。这意味着检查异常对象以使用引用,将具有未定义的行为。