我已经编程了很长一段时间C和C++,到目前为止,我从来没有使用异常和尝试/捕获。使用它的好处是什么,而不是只有函数返回错误代码?在C++中使用异常和try/catch而不是仅返回错误代码有什么好处?
回答
可能是一个明显的观点 - 开发人员可以忽略(或不知道)你的回报状态,并继续幸福地意识到某件事失败。
需要以某种方式承认异常 - 如果不主动提供适当的位置,不能默默忽略它。
您得到了以下两点之一:您可以轻松将用于处理错误的代码移动到非本地点(呼叫更改的较高位置),并知道如何在给定更广泛的上下文的情况下处理问题。 – 2008-12-10 05:12:33
异常处理很有用,因为它可以很容易地将错误处理代码与编写用于处理程序功能的代码分开。这使得阅读和编写代码变得更容易。
- 返回时发生错误情况预计在某些情况下
- 抛出一个异常时发生错误情况不预计在任何情况下
的错误代码函数的调用者必须检查错误代码是否有预期的失败;在后一种情况下,例外情况可由任何呼叫者在栈上(或默认处理程序)处理(如适用)
好处是,您不必在每次潜在呼叫失败后检查错误代码。为了让这个工作起来,你需要将它与RAII类结合起来,以便在堆栈展开时自动清理所有内容。
随着错误消息:
int DoSomeThings()
{
int error = 0;
HandleA hA;
error = CreateAObject(&ha);
if (error)
goto cleanUpFailedA;
HandleB hB;
error = CreateBObjectWithA(hA, &hB);
if (error)
goto cleanUpFailedB;
HandleC hC;
error = CreateCObjectWithA(hB, &hC);
if (error)
goto cleanUpFailedC;
...
cleanUpFailedC:
DeleteCObject(hC);
cleanUpFailedB:
DeleteBObject(hB);
cleanUpFailedA:
DeleteAObject(hA);
return error;
}
例外与RAII
void DoSomeThings()
{
RAIIHandleA hA = CreateAObject();
RAIIHandleB hB = CreateBObjectWithA(hA);
RAIIHandleC hC = CreateCObjectWithB(hB);
...
}
struct RAIIHandleA
{
HandleA Handle;
RAIIHandleA(HandleA handle) : Handle(handle) {}
~RAIIHandleA() { DeleteAObject(Handle); }
}
...
在乍看之下,RAII /例外版本似乎更长,直到你意识到,仅需要编写清理代码一次(并且有方法可以简化)。但DoSomeThings的第二个版本更加清晰和可维护。
不要试图在C++中使用异常而不使用RAII语言,因为会泄漏资源和内存。所有的清理都需要在堆栈分配对象的析构函数中完成。
我意识到还有其他的方式来做错误代码处理,但他们都看起来有点相同。如果你放弃goto,你最终会重复清理代码。
错误代码的一个要点是,它们明确了事情可能发生故障的位置以及它们如何失败。在上面的代码中,你假设事情不会失败(但是如果他们这样做,你会受到RAII包装的保护)。但是你最终不太理会事情会出错的地方。
Here's EAFP的一个很好的解释(“容易问宽恕比权限。”),我认为这适用于这里,即使它是维基百科的Python页面。使用例外会导致更自然的编码风格,海事组织 - 以及其他许多人的看法。
除了提到的其他内容,您不能从构造函数返回错误代码。也可以使用析构函数,但是也应该避免从析构函数中抛出异常。
正如@马丁指出抛出异常迫使程序员处理错误。例如,不检查返回代码是C程序中最大的安全漏洞来源之一。例外情况确保您处理错误(希望),并为您的程序提供某种恢复路径。如果您选择忽略异常而不是引入安全漏洞,那么您的程序将崩溃。
例外的优势有两个方面:
它们不能被忽略。你必须在某个级别处理它们,否则他们会终止你的程序。有了错误代码,您必须明确检查它们,否则它们会丢失。
它们可以被忽略。如果一个错误无法在一个层次上处理,它会自动在其可能的位置上升到下一个层次。错误代码必须显式传递,直到达到可以处理的级别。
有时你真的必须使用异常来标记异常情况。例如,如果在构造函数中出现错误,并且发现通知调用者这是有意义的,那么您别无选择,只能抛出异常。
又如:有时候没有价值你的函数可以返回来表示一个错误;函数可能返回的任何值都表示成功。
int divide(int a, int b)
{
if(b == 0)
// then what? no integer can be used for an error flag!
else
return a/b;
}
当我过去教C++时,我们的标准解释是,他们允许您避免纠结晴天和雨天的情况。换句话说,你可以编写一个函数,就好像一切都可以正常工作,并在最后捕获异常。
没有异常,你就一定得从每个调用的返回值,并确保它仍然是合法的。
当然,一个相关的好处是你不会“浪费”你的异常返回值(因此允许方法应该是无效的),并且还可以从构造函数和析构函数中返回错误。
我写这个博客条目(Exceptions make for Elegant Code),随后发表在Overload。我实际上是为了回应Joel在StackOverflow播客中所说的话而编写的!
无论如何,我坚信,例外是最好错误在大多数情况下代码。我发现使用返回错误代码的函数真的很痛苦:每次调用后都必须检查错误代码,这可能会中断调用代码的流程。这也意味着你不能使用重载操作符,因为没有办法指示错误。
检查错误代码的痛苦意味着人们经常忽视这样做,因此使它们完全没有意义:至少你必须明确地忽略与catch
声明的异常。
使用在C++析构函数和处置者在.NET,以确保资源在例外也可以极大地简化代码的存在正确释放。为了获得与错误代码相同的保护级别,您可能需要大量的if
语句,大量重复的清理代码或goto
调用在函数结束时的公用清理块。这些选项都不令人愉快。
事实上,你必须承认异常是正确的,但这也可以使用错误结构来实现。 您可以创建一个基本错误类,用于检查其dtor中是否调用了某个方法(例如IsOk)。如果没有,你可以登录一些东西,然后退出,或抛出异常,或提出断言等...
只要调用错误对象上的IsOk而不作出反应,那么将等同于写入catch (...){} 这两个陈述都会显示出同样缺乏程序员的善意。
将错误代码传输到正确的级别是一个更大的问题。基本上,为了传播的原因,几乎所有的方法都会返回一个错误代码。 但是,然后再次,一个函数或方法应该总是注释它可以生成的例外。所以基本上你必须有同样的问题,没有一个接口来支持它。
Google's C++ Style Guide对C++代码中异常使用的优缺点有很好的深入分析。这也表明你应该提出一些更大的问题;即我是否打算将我的代码分发给其他人(可能难以集成启用异常的代码库)?
- 1. 为什么抛出异常而不是返回错误代码更好?
- 2. 为什么fopen()或open()使用errno而不是仅仅返回错误代码?
- 3. 使用put和delete有什么好处,而不仅仅是获取和发布
- 4. 什么时候应该抛出异常而不是在PHP中返回错误?
- 5. 为什么不使用错误数组而不是异常处理?
- 6. 使用ORDBMS代替RDBMS有什么好处,而不是JPA
- 7. 从函数返回值而不是返回void有什么好处吗?
- 8. 使用calloc()而不是malloc()和memset()有什么好处吗?
- 9. 在“验证”类或返回状态代码中使用异常是否更好?
- 10. JavaScript返回“结果”而不是错误或异常
- 11. 为什么HttpWebRequest会抛出异常而不是返回HttpStatusCode.NotFound?
- 12. 使用Doctrine使用DQL而不是SQL有什么好处?
- 13. 未处理的异常返回垃圾字符,而不是错误
- 14. 为什么我的AJAX错误没有返回Webmethod异常?
- 15. 为什么它更好(返回IList而不是返回列表)?
- 16. 错误处理范例:混合异常和错误代码
- 17. Java中的异常和错误代码
- 18. Perl的异常而不是返回值
- 19. 使用分部类而不是抽象类有什么好处?
- 20. 使用Flux而不是for循环,有什么好处?
- 21. 使用名称而不是版本号有什么好处?
- 22. PHP:使用echo而不是print有什么好处?
- 23. 使用Spring DataAccessExceptions而不是JPA PersistenceExceptions有什么好处吗?
- 24. 使用BIO_printf()而不是printf()有什么好处?
- 25. 使用* .component.scss而不是将其写入styles.scss有什么好处?
- 26. 使用SPL ArrayObject,ArrayIterator,RecursiveArrayIterator而不是常规数组有什么好处?
- 27. Postgresql,异常返回错误
- 28. 意大利面代码,处理异常处理和错误?
- 29. OpenCL:为什么使用clEnqueueMapBuffer崩溃而没有返回错误?
- 30. 为什么我的异常处理代码没有处理异常?
查看James Curran的答案为__> 2 <__的主要原因。 – 2008-12-10 05:13:27