1

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

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抛出什么()返回“map.at”)的异常,那么传递附加信息的好策略是什么?请注意,即使连接多个字符串,在构建错误消息期间理论上也可能导致 bad_alloc。IE:

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
    }
}
4

2 回答 2

4

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

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

当控制从抛出异常的点传递到处理程序时,将为自进入 try 块以来构造的所有自动对象调用析构函数。自动对象按照其构建完成的相反顺序被销毁。

于 2014-12-06T22:31:30.520 回答
3

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

于 2014-12-06T22:31:39.183 回答