2010-06-07 81 views
3

我有某种意识形态的问题,所以:C++ - 在哪里抛出异常?

假设我有一些模板函数

template <typename Stream> 
void Foo(Stream& stream, Object& object) { ... } 

这确实与此objectstream(例如东西,连载该对象流或类似的东西)。

比方说,我还添加一些简单的封装类,如(并假设这些包装的数量等于2或3):

void FooToFile(const std::string& filename, Object& object) 
{ 
    std::ifstream stream(filename.c_str()); 
    Foo(stream, object); 
} 

所以,我的问题是:

在这种情况下(思想上),如果我的stream不好,我应该抛出异常吗?我应该这样做在每个包装或只是动议通过检查我的Foo,所以它的机身看起来像

if (!foo.good()) throw (something); 
// Perform ordinary actions 

我明白,这可能是没有编码的最重要组成部分,这些解决方案实际上是相等的,但我只是想知道“适当的”方式来实现这一点。

谢谢。

回答

5

在这种情况下,最好将它放在更低层的Foo函数中,这样就不必在所有包装中复制验证和异常抛出代码。一般情况下,正确使用异常可以通过删除大量的数据验证检查来使代码更加清晰,否则可能会在调用堆栈中的多个层次上进行冗余。

+1

+1:避免剪切和粘贴是编程的最终目标:) – neuro 2010-06-07 15:47:33

1

越快抓住例外就越好。例外情况越具体 - 越好。除了声明之外,不要害怕将大部分代码包含在try catch块中。

例如:

int count = 0; 
bool isTrue = false; 
MyCustomerObject someObject = null; 

try 
{ 
    // Initialise count, isTrue, someObject. Process. 
} 
catch(SpecificException e) 
{ 
// Handle and throw up the stack. You don't want to lose the exception. 
} 
1

我喜欢使用辅助功能此:

struct StreamException : std::runtime_error 
{ 
    StreamException(const std::string& s) : std::runtime_error(s) { } 
    virtual ~StreamException() throw() { } 
}; 

void EnsureStreamIsGood(const std::ios& s) 
{ 
    if (!s.good()) { throw StreamException(); } 
} 

void EnsureStreamNotFail(const std::ios& s) 
{ 
    if (s.fail()) { throw StreamException(); } 
} 

我之前和执行流操作,如果我不希望在发生故障后,立即对其进行测试。

1

传统上在C++中,流操作不会抛出异常。这部分是由于历史原因,部分原因是流式传输故障预计会出现错误。 C++标准流类处理这个问题的方式是在流上设置一个标志,以表明发生了错误,哪些用户代码可以检查。不使用异常使得恢复(流操作通常需要)比抛出异常更容易。

+0

尽管如此,如果在发生不好的事情时想要有异常,那么总会有流对象的异常掩码。在我看来,它应该设置为* badbit *:正如你所说的那样,除了eOF之外,还有提取失败的情况,但是如果存在IO错误,那么你可以做的事情不多,至少不是在你的“正常”文件读/写代码。 – 2010-06-07 16:44:58

2

我不希望延迟通知错误。如果您在创建流之后知道它不好,为什么调用一个可用于它的方法?我知道,为了减少代码冗余,您计划进一步降低代码冗余。但这种方法的缺点是一个不太具体的错误信息。所以这在一定程度上取决于源代码上下文。如果您可以在较低功能级别避免使用通用错误消息,则可以在其中添加代码,这肯定会缓解代码的维护,特别是在团队中有新开发人员时。如果你需要一个特定的错误信息,那么最好在失败点处理它。

为了避免代码冗余,请调用一个常见的函数,为您创建此异常/错误。不要在每个包装中复制/粘贴代码。