包含类变量初始化的C ++类初始化
我注意到今天某位同事的一些代码在初始化过程中初始化了类变量。他说,但是这引起了警告,因为它们的顺序。我的问题是,为什么最好在当前所在的位置而不是在大括号内进行变量初始化?
DiagramScene::DiagramScene( int slideNo, QRectF screenRect, MainWindow* parent ) : QGraphicsScene( screenRect, parent ), myParent( parent ), slideUndoImageCurrentIndex(-1), nextGroupID(0), m_undoInProgress(false), m_deleteItemOnNextUndo(0) line(0), path(0) { /* Setup default brush for background */ scDetail->bgBrush.setStyle(Qt::SolidPattern); scDetail->bgBrush.setColor(Qt::white); setBackgroundBrush(scDetail->bgBrush); }
解决方案
- (通常)效率更高。无论是否显式初始化类的所有成员,都必须在构造函数中对其进行初始化。如果未指定初始化程序,则将运行成员的默认构造函数。如果在构造函数主体中分配值,则将再次调用赋值运算符。就像示例一样,这不适用于标量值,因为标量值没有构造函数。
- 我们不能在初始化列表中不小心分配了两次值。
- 编译器可以检查以确保编写初始化程序的顺序与在类中定义成员的顺序匹配。 C ++标准要求成员以声明的顺序进行初始化,无论我们编写初始化程序的顺序如何。让编译器检查此顺序可确保程序员知道初始化程序将以哪个顺序运行(再次,对于非POD成员,此操作比标量更重要)。
- 引用类型和const成员必须在初始化程序列表中进行初始化,因为我们不能分配给引用或者const成员。
因为,在构造函数的主体中("在大括号内"),成员变量已经是默认构造的。当我们拥有一个具有非平凡构造的类型的成员变量时,当我们首先对其进行默认构造时,然后在构造器中为其分配其他值时(当我们可以进行自定义构造时),这可能会影响性能它直接。
另外,某些类型可能不是默认构造的(例如,引用),必须在初始化列表中构造。
在http://web.tiscali.it/fanelia/cpp-faq-zh/ctors.html#faq-10.6上查看所收集的智慧
如果我们有const变量,则不能通过赋值设置它们的值。
将值分配给对象(非内置或者内部函数)时,初始化也更加有效,因为不会像分配那样创建临时对象。
有关更多详细信息,请参见C ++ FAQ-Lite。
最好在初始化列表中对成员进行初始化,因为成员仅被初始化一次。如果成员本身是类,那么这在性能(甚至行为)上可能会有巨大的差异。如果成员都是非常量,非引用基本数据类型,则差异通常可以忽略不计。
注意:有时,基本数据类型需要初始化列表-特别是如果类型为常数或者引用。对于这些类型,数据只能初始化一次,因此无法在构造函数的主体中初始化。有关更多信息,请参见本文。
请注意,成员的初始化顺序是在类定义中声明成员的顺序,而不是在初始化列表中声明成员的顺序。如果可以通过更改初始化列表的顺序来解决警告,那么我强烈建议我们这样做。
我的建议是:
- 我们将学习喜欢初始化列表。
- 同事了解成员初始化顺序的规则(并避免出现警告)。
除了Greg Hewgill的出色回答外,还必须在初始化列表中设置const变量。
Greg答案的另一项补充:类型为无默认构造函数的成员必须在初始化列表中进行初始化。
Greg Hegwell的答案包含了一些很好的建议,但是并不能解释为什么编译器会生成警告。
当编译器处理构造函数的初始化程序列表时,项目将按照在类声明中声明的顺序进行初始化,而不是按照它们在初始化程序列表中出现的顺序进行初始化。
如果初始化程序列表中的顺序与声明顺序不同,则某些编译器会生成警告(因此,如果未按列表顺序初始化项,我们将不会感到惊讶)。我们不包括类声明,但这可能是我们看到警告的原因。
此行为的基本原理是,类的成员应始终以相同的顺序进行初始化:即使该类具有多个构造函数(在其构造函数列表中,成员的排列顺序也可能不同)。