0

这似乎是一个奇怪的问题。我目前正在将某些对象从两步初始化方案转移到一步初始化方案。基本上将成员函数中所做的事情.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 语句来处理这种情况?

4

4 回答 4

5

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

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

于 2012-07-20T23:27:29.237 回答
2

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

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

};

这样,您将两步初始化封装为单向初始化。

于 2012-07-21T16:04:23.383 回答
1

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

如果您真的反对例外,我建议您使用此表格:

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

但是单独的initialize方法会更好。

于 2012-07-20T23:14:52.683 回答
1

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

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

编辑:忘了添加,如果你重载 new 你需要用 malloc 和重载 delete 保留内存。

于 2012-07-20T23:17:42.387 回答