繁体   English   中英

C++ 来自没有 try/catch 块的构造函数的异常处理

[英]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);之后和/或之前。 检查inputgoodeoffail和/或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;
};

如果没有stdoptional可能会很快实现(有几个警告,但它可能已经足够好了),例如:

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:
    // ...
};

我会为AB添加流式操作符( 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM