C ++ - 在哪里抛出异常?

时间:2010-06-07 15:39:18

标签: c++ exception stream

我有某种意识形态问题,所以:

假设我有一些模板化函数

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 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:2)

我不想延迟通知错误。如果你知道在创建了流之后,那就不好了,为什么要调用一个适合它的方法呢?我知道为了减少代码冗余,你计划进一步降低代码冗余。但该方法的缺点是一个不太具体的错误消息。所以这在某种程度上取决于源代码上下文。如果您可以在较低功能级别获得通用错误消息,则可以在其中添加代码,这肯定会简化代码的维护,尤其是当团队中有新的开发人员时。如果您需要特定的错误消息,请在故障点处更好地处理它。

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

答案 2 :(得分: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.
}

答案 3 :(得分: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(); }
}

如果我不期望失败,我会在执行流操作之前和之后立即测试它们。

答案 4 :(得分:1)

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