[英]C++ exception handling from constructors without try/catch blocks
在我目前正在进行的一个学校项目中,我们必须写入和读取二进制文件。 为了使我的代码更优雅,我选择在其中一个类中使用序列化 ctor,这些类接收一个 ifstream 以从文件中读取以获取其适当的数据。
我们的要求之一是我们需要检查文件是否成功读取,但目前还不允许以 try-catch 块的形式实现异常处理。 因此,如果读取不成功,我能想到的唯一选择是返回 boolean 值。 问题是我有嵌套类,例如第一个 class 看起来像:
class A
{
public:
A(ifstream& input)
{
// read data from input //
// call load method of nested class B //
}
private:
// some data //
B b;
};
并且嵌套的 class 将调用其加载方法来读取适当的数据,而不是具有接收文件的 ctor,因此 B 将如下所示:
class B
{
public:
void load(ifstream& input);
private:
// some data //
};
处理异常的替代方法是什么,或者您建议对我的代码进行哪些更改以使其符合项目要求?
使 B 的加载方法 boolean 并返回 false 例如如果读数不好会导致我回到 A 的 ctor,我无法从中返回值。
我现在在 C++ 中编码了几个月,所以如果这里的某些东西看起来像是糟糕的设计或明显错误,我深表歉意 - 也将不胜感激任何反馈。 谢谢你。
默认情况下,iostream 没有启用异常。 在std::istream
object 上启用异常通常是一个非常糟糕的主意。 所以我不会指望它是活跃的。
将std::ifstream
更改为std::istream
。 这将使代码在测试中必须更加灵活,因为它不再需要ifstream
并且您可以在调用代码时使用std::istringstream
进行测试。
建议将load
的API改为
std::istream& load(std::istream& input);
这与大多数其他 iostream 运算符一致,它只返回input
变量。 它使调用者更容易管道调用。
A::A(std::istream& input)
中的代码可以在调用b.load(input);
之后和/或之前。 检查input
的good
、 eof
、 fail
和/或bad
的结果。 这应该足以决定如何设置您的bool
以传达适当的失败。
如果你不能从构造函数中抛出,你可能需要一个 static 工厂,它也允许返回“错误” 。
有std::expected<T, Error>
的建议,但尚不可用,某些库可能会提出等效建议。
目前可能的方法包括使用std::optional
或(智能)指针:
class B
{
B() = default;
public:
static std::optional<B> load(std::istream& input)
{
B b;
// read input...
if (errorDetected) { return std::nullopt; }
return b;
}
private:
// some data
};
class A
{
public:
static load(std::istream& input)
{
A a;
// read data from input
if (errorDetected) { return std::nullopt; }
auto b = B::load(input);
if (!b) return std::nullopt;
a.b = std::move(*b);
return a;
}
private:
// some data
B b;
};
如果没有std
, optional
可能会很快实现(有几个警告,但它可能已经足够好了),例如:
template <typename T>
class my_poor_optional
{
T data; // required to be constructed, even when invalid contrary to real optional
bool is_valid = false;
public:
// ...
};
我会为A
和B
添加流式操作符( operator>>
和operator<<
),而不是使用转换构造函数和load
成员 function。
例子:
class B {
public:
friend std::istream& operator>>(std::istream& is, B& b) {
return is >> b.b_data;
}
friend std::ostream& operator<<(std::ostream& os, const B& b) {
return os << b.b_data;
}
private:
int b_data;
};
class A {
public:
friend std::istream& operator>>(std::istream& is, A& a) {
return is >> a.a_data
>> a.b; // uses B's operator>>
}
friend std::ostream& operator<<(std::ostream& os, const A& a) {
return os << a.a_data << ' '
<< a.b; // uses B's operator<<
}
private:
int a_data;
B b;
};
然后,您可以从文件中检查 stream 并检查 stream 的 state 以查看提取是否有效:
// ...
A foo;
if(input >> foo) { // input is true in boolean contexts if extraction succeeds
std::cout << "Successfully read an A: " << foo;
} else {
std::cerr << "Failed reading from stream\n";
}
如果您想确保 IO 操作不应该在错误时引发异常,您可能想查看basic_ios
的异常掩码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.