初始化抛出异常的对象

时间:2018-04-09 16:01:22

标签: c++

我有A类,它有构造函数A(字符串文件路径)

class A {
  public:
    A(string filePath);
  private:
    A();
}

我需要初始化A,稍后再使用它。构造函数A抛出异常。

int main() {
    A a;
    try {
        a = A("./my/file/path");
    } catch (exception e) {
        return 1;
    }
    // Use a
    return 0;
}

最优雅的解决方案是什么? (我不想拥有类似init函数的东西,因为它可以使空A对象成为可能。)

4 个答案:

答案 0 :(得分:4)

最优雅的解决方案可能是将所有使用a的逻辑移动到函数

int use_a(A &a);

int main() {
    try {
        A a("./my/file/path");
        // if we reach here, no exception was thrown
        // hence a is safe to use
        return use_a(a);
    } catch (exception e) {
        // if we reach here a never really existed
        return 1;
    }
}

您更愿意避免两阶段初始化 - 这种方式use_a可以隐含地依赖a安全使用。

答案 1 :(得分:2)

最优雅的解决方案是:

int main() {
   try {
      A a("...");
      // use a
   } catch (const std::exception& e) {
      // log e
      return 1;
   }

   return 0;
}

答案 2 :(得分:1)

如果您不想要空A对象,请考虑删除默认构造函数。请注意,这使得使用某些stl容器更加困难,同时确保不存在无效对象。

除此之外,我认为使用throw in constructors非常允许。如果您不想这样做,请考虑noexcept关键字。请注意,析构函数中的抛出可能会导致问题并且通常会被避免。

答案 3 :(得分:1)

作为替代方案,您可以在"可选/可检查"中转换例外。使用std::optionalstd::unique_ptr构建

std::optional<A> MakeA(const std::filesystem::path& path)
{
    try {
        return A{path};
    } catch (std::exception& e) {
        return std::nullopt;
    }
}

int main() {
    auto a = MakeA("./my/file/path");
    if (!a) {
        return 1;
    }
    // Use *a
    return 0;
}