我有某种意识形态问题,所以:
假设我有一些模板化函数
template <typename Stream>
void Foo(Stream& stream, Object& object) { ... }
对此object
和stream
执行某些操作(例如,序列化该对象与流或类似内容)。
假设我还添加了一些像这样的普通包装器(假设这些包装器的数量等于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
我知道这可能不是编码中最重要的部分,这些解决方案实际上是相同的,但我只是不知道“正确的”方式来实现它。
谢谢。
答案 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 ++标准流类处理此问题的方法是在流上设置一个标志,以指示发生了错误,用户代码可以检查。不使用异常使得恢复(流式操作通常需要恢复)比抛出异常更容易。