两步到一步的初始化和错误处理

Two-step to One-step initialization and error handling

本文关键字:初始化 处理 错误 两步 一步      更新时间:2023-10-16

这似乎是一个奇怪的问题。我目前正在将某些对象从两步初始化方案移动到一步初始化方案。基本上将.initialize().terminate()成员函数中的操作转移到构造函数和析构函数中。

我的问题是,重要的是要知道这些类是否正确初始化了某些依赖于外部因素的属性。

一个例子是我的Window类,它创建了一个WinAPI窗口。以前使用两步方法时,我会让initialize()返回一个布尔值,表示窗口是否正确创建。

if(myWindow.initialize())
{
    // proceed with application
}
else
{
    // exit
}    

是否有任何方法可以在不创建和调用第二个方法(如didMyWindowInitializeCorrectly())的情况下从构造函数中继此信息?

起初,我希望有一些类似的东西

if(Window *myWindow = new Window)
{
    // proceed with application
}
else
{
    // exit
}

但这不会起作用,因为即使窗口创建失败,Window对象仍将实例化。

唯一的解决方案是让构造函数抛出异常,然后捕获它并继续吗?我看了很多线程,人们对C++异常的看法似乎很不一致,所以我不确定什么是最好的方法。

有没有办法用if语句来处理这种情况?

这归结为基于异常或错误代码的初始化的大参数。我通常更喜欢Exceptions来指示构造函数失败,因为当问题没有在稍后的代码中通过is_valid检查或忽略两步返回值来处理时,问题在堆栈跟踪的早期变得更加明显。它还更清楚地说明了初始化失败的原因,而无需查找错误代码。那些喜欢传统的C风格而不是异常风格的失败消息传递的人可能会在最后一点上不同意我的观点。

然而,与代码库的其余部分的风格相匹配通常是个好主意。因此,如果代码中的其他地方没有使用Exceptions,那么最好进行is_valid检查(或原始的两阶段初始化),而不是引入对象验证机制。我更喜欢is_valid,而不是像Riateche发布的两个阶段,因为它让用户能够选择是否/何时检查它是否有效,而无需在合法使用对象之前查找必须调用的函数。

您可以做的一件事是创建一个执行两步初始化的静态方法,即

class Window {
  public:
     static Window* createWindow() {
          Window* w = new Window();
          if (w->isValid()) {
            return w;
          }
          delete w;
          return NULL;
     }
  private:
    Window();
    bool isValid();
};

通过这种方式,您将两步初始化封装为单向初始化。

我当然会使用异常,但如果出于任何原因不需要,您可以覆盖新的运算符,并在出现错误时返回NULL。(只是别忘了释放你的记忆)然后再回来。

void* T::operator new(size_t x);

edit:忘记添加,如果重载new,则需要使用malloc保留内存,并重载delete。

在这种情况下可以使用异常。通常,构造函数必须始终返回有效对象或引发异常。

如果你真的反对例外情况,我建议你使用以下表格:

Window my_window;
if (!my_window.is_valid()) {
  cout << "fail";
  return;
}

但单独的initialize方法会更好。