如何在没有体操的情况下调用返回引用或抛出异常的函数?

时间:2014-02-26 02:26:33

标签: c++ exception reference

假设您看到以下代码:

blah & Foo::foo() { 
   if (_x) {  return _blah;}
   throw exception("blah error");
}

据我所知,调用它的唯一方法是在try / catch块中这样做

try {
blah &b=_foo.foo();
catch(...) {}

现在b超出范围,使得错误处理有些困难。可以将它分配给指针,然后将指针重新分配给下面的引用,但这似乎相当困难。

我不记得有一个明确的建议是避免创建返回引用或抛出异常的函数,但在处理这些类型的接口时是否有一种解决此问题的标准方法?

4 个答案:

答案 0 :(得分:2)

你身边似乎存在误解。如果上面的函数抛出异常,它就不会完成,而会产生一个引用。 try/catch块内的引用不仅无法访问,而且甚至从未存在

抛出异常的函数返回。

答案 1 :(得分:1)

正如克里斯在他的评论中已经提到过的那样,你确实会处理与返回代码不同的异常,因为你没有包装可能会抛出自己的try / catch处理程序的每个函数调用。

不像检查返回代码那样检查异常(在每次函数调用之后),而是将异常处理推送到最适合处理由异常发出信号的故障的层。那个可能是你当前代码的几层。

对于返回引用,有一些指导原则,例如不返回对本地对象的引用。在您的情况下,您可能会返回对成员的引用,只要您确保不会遇到对象生命周期问题,这可能就行了。

答案 2 :(得分:0)

嗯,诀窍是设计异常,异常处理程序和错误处理程序,这样就不会遇到这样的情况。例如,您可以在foo()块中包含依赖于try成功返回的所有操作,这样您就可以处理所有这些操作引发的异常。曾经的地方。从概念上讲,您“试图”执行整个任务,而不是尝试独立执行各个步骤,例如:

try { 
    blah &b = _foo.foo();
    b.dehydrate();
    _foo.reconceptualize(b);
    idealize(b, _foo, "grumble");
} catch (const exception &x) {
    // log/handle error
}

另一种思考方式是,如果引用b的有效性取决于foo()的成功,则代码中只有一个地方b有效,在调用try之后的foo()块中。一旦您离开try区块,就无法保证b的有效性,因为此时可能会发生或可能不会发生异常。

try {
    blah &b = _foo.foo();
    // <- [1] this is the only point that we *know* foo() returned something valid
} catch (...) {
    // <- [2] here we *know* it didn't
}

// <- [3] here we don't know either way

现在,如果您的代码依赖于foo()的成功和b的有效性,并且您必须选择上面的位置1,2或3,这似乎是最适合您的(提示) :1)?

即使你使用了在try块之前声明的指针,使用例如它也是相当多余的。当您已经获得以前可用的信息时,NULL表示引发了异常:

blah *b;

try {
    b = _foo.fooptr();
    // <- here we know an error did not occur
} catch (...) {
    // <- here we know an error occurred
    b = NULL; // <- so why do this...
}

// ... when we already had a perfectly good opportunity to handle above;
// we've kind of missed the boat at this point.

这并不是说没有指针示例没用的情况。也许你不关心做任何特殊的错误处理,或者你正在抽象一些其他的API:

void * getData () {
    void *data = NULL;
    try {
        data = getFromThingThatMayThrow();
    } catch (...) {
        // we really don't care why it failed, and it's more convenient to
        // swallow it and return NULL instead.
    }
    return data;
}

但回首点是,如果你发现你的异常处理变得非常奇怪和混乱,就像在你的例子中一样,你可能会走错路,你应该考虑退一步并重新评估你的错误处理。如果使用得当,例外可以极大地简化错误处理和恢复。

答案 3 :(得分:0)

像C ++ 1y optional这样的东西可能对此有所帮助。我也看到了expected<T,Otherwise>的提案。您将调用捆绑为带有引用或错误信息的伪联合。您可以随时处理错误,如果检查了错误,则可以访问数据。

这导致传统的内联错误处理,而不是基于异常的“来自”错误处理,有些人更喜欢。