【问题标题】:Throwing non-const temporaries by reference通过引用抛出非常量临时对象
【发布时间】:2010-02-16 16:57:37
【问题描述】:

通过非常量引用在try-block中抛出一个构建在堆栈上的对象,捕获并修改它,然后通过引用另一个catch块抛出它有什么问题吗?

以下是我所指内容的简短示例。

struct EC {
    EC(string msg) { what = msg; }
    string where;
    string what;

    void app(string& t) { where += t; }
    string get() { return what; }
};

try {
    try {
        try {
            EC error("Test");
            throw error;
        }
        catch (EC& e) {
            e.app("1");
            throw e;
        }
    }
    catch (EC& e) {
        e.app("2");
        throw e;
    }
}
catch (EC& e) {
     e.app("3");
     cout << e.where << endl;
     cout << e.get() << endl;
}

这是否可能导致 e.what 包含垃圾,但 e.where 保持不变?例如:
e.哪里是“123”
e.get() 返回大量垃圾数据,直到碰巧碰到一个空字节。

【问题讨论】:

  • 无法复制。也不会使用 app() 中的非常量引用进行编译。在任何情况下,您都不会抛出引用,而是抛出副本。
  • 这不是用来编译的。该代码只是说明了我所指的内容。我问这样的事情是否会导致 e.get() 包含垃圾数据,而不是它是否可以编译和工作。
  • 鉴于这不是真正的代码,如果需要复制构造函数,e.get() 返回垃圾的可能性不大。

标签: c++ exception undefined-behavior


【解决方案1】:

没有“通过引用抛出”这样的东西。这简直是​​不可能的。没有语法。每次尝试“抛出引用”时,实际上都会抛出被引用对象的副本。不用说,在您的代码中没有尝试通过引用抛出。

可以捕获通过引用(甚至是非常量的)先前抛出的异常,并通过它修改临时异常对象。它会起作用的。事实上,您可以重新抛出现在修改的 existing 异常对象,而不是创建一个 new 异常对象。 IE。你可以这样做

throw;

而不是

throw e;

在您的 catch 子句中,仍然可以获得行为正确的代码,即原始对象(带有修改)将继续通过处理程序层次结构飞行。

但是,您的代码格式不正确

e.app("1"); 

调用(以及对app 的其他调用),因为参数是非常量引用。将 app 声明更改为

void app(const string& t) { where += t; }  // <- either this
void app(string t) { where += t; }         // <- or this

编译。

否则,您的代码应该可以正常工作。你不应该从get() 得到任何垃圾。如果你这样做了,那一定是你的编译器有问题,或者你的代码没有显示。

【讨论】:

  • 可能值得一提的是,您应该通过 ref 捕获以避免对象切片
  • 如果我有 MyClass obj 然后是 throw &amp;obj 会发生什么?这是抛出一个引用吗?
  • @CătălinaSîrbu 不,你为什么还要在这种情况下提到参考资料?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
相关资源
最近更新 更多