1

我一直在做一些阅读,一般意见似乎是尽可能避免两阶段初始化。我同意它所说的大部分内容。但我发现它不是那么容易消除的。

这是一个完全虚构的示例,尽管强烈基于一些真实代码 -

想象一下我正在开发一个游戏。主游戏类需要构造一个执行 3D 渲染的“RenderDevice”对象。但是为了构建它,它需要从配置文件中加载一些设置。和一个要绘制的 Window 对象。还有一个记录器对象和一个内存池。我的代码现在将所有这些东西作为类成员,构造函数做的很少,然后使用相关参数在每个对象上调用一个 init 函数,例如:-

// Much simplified code to make a point
Game::Game()
{
    memoryPool_.init(10000000); // Amount of memory to allocate
    logger_.init("logfile.txt", memoryPool_);
    window_.init(2000, 1000);   // Make a nice big window
    renderDevice_.init(window_, logger_, memoryPool_);
}

对我来说,这似乎工作得很好。但这是两个阶段。每个对象仅由其构造函数部分构造。所以我不得不做类似这样的事情来使代码“干净”。

Game::Game() :
    memoryPool_(1000000),
    logger_("logfile.txt", memoryPool_),
    window_(2000, 1000),
    renderDevice_(window_, logger_, memoryPool)
{
}

现在该代码对我来说似乎相当丑陋,但也相当脆弱,因为初始化的顺序取决于它们在类中声明的顺序,而不是此处列出的顺序。随着越来越多的数据被添加到类中,情况会变得更糟。这里的对象只需要几个参数,但如果它们需要更多数据,这将很快失控。

它的优点是每个对象都准备好完成它的工作,但它对我来说看起来很丑,而且看起来相当脆弱且容易出错......

所以我的问题是我错过了重点吗?有一个更好的方法吗?我应该停止担心并这样做,还是应该使用我的原始代码?或者我的整个设计在某种程度上在更高层次上是错误的,所以这个问题没有用?

基本上什么是最佳实践?

4

2 回答 2

8

现在该代码对我来说似乎相当难看

在我看来不是这样。也许你只是不习惯?

相当脆弱,因为初始化的顺序取决于它们在类中声明的顺序,而不是此处列出的顺序

打开编译器的警告,它应该告诉您这两个命令之间的不匹配。(我知道 Clang 有这个警告,我很确定 GCC 也有。不太确定 MSVC。)

这里的对象只需要几个参数,但如果它们需要更多数据,这将很快失控。

当您使用init().

于 2013-08-27T21:37:40.580 回答
0

根据我的经验,init 函数用于可能出现错误和无法使用/抛出异常的地方。您提到的示例都有错误情况,并且似乎只是抛出异常,因为没有检查返回值。

我认为从 Game 中的 init 函数调用一组 init 而不是从构造函数本身调用 init 是一种很好的做法。

于 2013-08-27T22:25:53.063 回答