假设您看到以下代码:
blah & Foo::foo() {
if (_x) { return _blah;}
throw exception("blah error");
}
据我所知,调用它的唯一方法是在try / catch块中这样做
try {
blah &b=_foo.foo();
catch(...) {}
现在b超出范围,使得错误处理有些困难。可以将它分配给指针,然后将指针重新分配给下面的引用,但这似乎相当困难。
我不记得有一个明确的建议是避免创建返回引用或抛出异常的函数,但在处理这些类型的接口时是否有一种解决此问题的标准方法?
答案 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>
的提案。您将调用捆绑为带有引用或错误信息的伪联合。您可以随时处理错误,如果检查了错误,则可以访问数据。
这导致传统的内联错误处理,而不是基于异常的“来自”错误处理,有些人更喜欢。