简体   繁体   English

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

[英]Two-step to One-step initialization and error handling

This may seem like an odd question. 这似乎是一个奇怪的问题。 I'm currently moving certain objects from a two-step to a one-step initialization scheme. 我目前正在将某些对象从两步式迁移到一步式初始化方案。 Basically moving what was done in the .initialize() .terminate() member functions into the constructors and destructors. 基本上将.initialize() .terminate()成员函数中执行的操作移到构造函数和析构函数中。

My issue is that, it is important to know whether or not these classes initialized certain attributes correctly that depend on external factors. 我的问题是,重要的是要知道这些类是否正确初始化了依赖于外部因素的某些属性。

An example is my Window class which creates a WinAPI window. 我的Window类就是一个例子,它创建一个WinAPI窗口。 Previously using the two step method I would have initialize() return a boolean of whether or not the window was created properly. 以前使用两步方法,我将拥有initialize()返回是否正确创建窗口的布尔值。

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

Is there anyway to relay this information from the constructor without creating and having to call a second method, such as didMyWindowInitializeCorrectly() ? 无论如何,是否有必要从构造函数中中继此信息,而无需创建并调用第二个方法,例如didMyWindowInitializeCorrectly()

At first I was hoping something along the lines of 起初,我希望有一些类似的东西

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

But this won't work because the Window object will still instantiate even though the window creation failed. 但这将不起作用,因为即使窗口创建失败,Window对象仍将实例化。

Is the only solution to have the constructor throw an exception and then catch it and proceed? 是使构造函数引发异常然后捕获并继续的唯一解决方案吗? I've looked at a lot of threads and people's opinions of C++ exceptions seems pretty split so I'm unsure of what is the best approach. 我看了很多线程,人们对C ++异常的看法似乎分歧很大,所以我不确定什么是最佳方法。

Is there anyway to handle this situation with an if statement? 无论如何,是否可以使用if语句来处理这种情况?

This comes down to the big argument of Exception or error code based initialization. 这归结为基于异常或基于错误代码的初始化的重要论点。 I usually prefer Exceptions for indicating constructor failure as the problem becomes more apparent earlier in a stack trace when the problem isn't handled over is_valid checks later in code or ignoring two-step return values. 我通常更喜欢使用Exceptions来指示构造函数失败,因为当问题没有通过稍后的is_valid检查在代码中解决或忽略两步返回值时,问题在堆栈跟踪中更早变得更加明显。 It's also clearer about why initialization failed without needing error code lookups. 关于为什么初始化失败而无需错误代码查找的信息也更加清楚。 People who prefer the conventional C style over Exception style failure messaging will probably disagree with me on that last point. 在最后一点上,喜欢常规C样式而不是Exception样式失败消息传递的人可能会与我不同意。

However, it's oftentimes a good idea to match the style of the rest of the code base. 但是,匹配其余代码库的样式通常是一个好主意。 So if Exceptions aren't used anywhere else in the code, it's probably better to have a is_valid check (or the original two stage initialization) over introducing a mechanism for object validation. 因此,如果在代码的其他任何地方都没有使用异常,则最好使用is_valid检查(或原始的两阶段初始化),而不是引入对象验证机制。 I prefer the is_valid over two stage much like Riateche posted, as it leaves the user capable of choosing if/when they want to check it's valid without needing for them to go lookup what functions have to be called before they should legally use the object. 我更喜欢像Riateche那样在两个阶段使用is_valid,因为它使用户能够选择是否/何时要检查其是否有效,而无需他们去查找在合法使用该对象之前必须调用的函数。

One thing that you could do, is create a static method that does your two-step initialization, ie 您可以做的一件事,就是创建一个静态方法来进行两步初始化,即

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

};

In that way, you are encapsulating your two-step initialize into a one-way initialize. 这样,您将两步初始化封装为单向初始化。

Using exceptions is OK in this case. 在这种情况下,可以使用异常。 Normally, a constructor must always return a valid object or throw an exception. 通常,构造函数必须始终返回有效对象或引发异常。

If you are really against exceptions, I suggest this form for you: 如果您确实反对例外,建议您使用以下表格:

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

But a separate initialize method would be better. 但是单独的initialize方法会更好。

I would certainly use exceptions, but if don't want for any reason, you could override the new operator and return NULL in case of error. 我当然会使用异常,但是如果出于任何原因不希望使用异常,则可以覆盖新的运算符,并在出现错误的情况下返回NULL。 (Just don't forget to release your memory) before returning. 返回之前(请不要忘记释放您的记忆)。

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

edit: forgot to add, if you overload new you need to reserve memory with malloc and overload delete also. 编辑:忘记添加,如果您过载了new,则需要使用malloc保留内存,并且还要过载delete。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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