MST

星途 面试题库

面试题:C++初始化列表与构造函数体内赋值的性能差异

详细阐述C++类构造函数初始化列表和在构造函数体内进行成员变量赋值,在性能方面有哪些不同?在何种情况下,使用初始化列表能显著提升性能?请通过代码示例进行分析。
35.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

性能差异

  1. 初始化列表
    • 直接初始化成员变量,对于类类型成员变量,会调用其对应类型的构造函数进行初始化。这种方式效率较高,特别是对于那些没有默认构造函数,或者在默认构造函数之后还需要进行额外赋值操作的成员变量。
    • 因为成员变量在进入构造函数体之前就已经被初始化完成,减少了构造函数体内可能的额外赋值开销。
  2. 构造函数体内赋值
    • 先调用成员变量的默认构造函数(如果存在),然后在构造函数体内再进行赋值操作。这意味着对于每个成员变量,可能会有一次默认构造和一次赋值操作,相比初始化列表会有更多的开销。

显著提升性能的情况

  1. 成员变量为类类型且没有默认构造函数
    • 如果类类型成员变量没有默认构造函数,必须使用初始化列表来初始化,否则无法通过编译。例如:
class NoDefaultConstructor {
public:
    NoDefaultConstructor(int value) : data(value) {}
private:
    int data;
};

class MyClass {
public:
    // 必须使用初始化列表初始化noDefault
    MyClass(int value) : noDefault(value) {}
private:
    NoDefaultConstructor noDefault;
};
  • 如果尝试在构造函数体内赋值,如MyClass(int value) { noDefault = NoDefaultConstructor(value); },编译器会报错,因为noDefault在进入构造函数体前需要先默认构造,而该类型没有默认构造函数。
  1. 成员变量为const类型或引用类型
    • const类型和引用类型的成员变量必须在定义时初始化,所以只能在初始化列表中进行初始化。例如:
class ConstAndRefClass {
public:
    ConstAndRefClass(int& refValue) : ref(refValue), constant(10) {}
private:
    int& ref;
    const int constant;
};
  1. 频繁构造和析构的场景
    • 当对象频繁构造和析构时,使用初始化列表减少不必要的默认构造和赋值操作能显著提升性能。例如,在一个循环中构造大量对象:
#include <iostream>
class Example {
public:
    Example(int value) : data(value) {}
private:
    int data;
};

int main() {
    for (int i = 0; i < 1000000; ++i) {
        Example ex(i);
    }
    return 0;
}
  • 如果使用构造函数体内赋值,每次构造对象时会多一次默认构造和一次赋值操作,在大量构造的场景下,性能损耗会比较明显。

综上所述,在上述几种情况下,使用初始化列表能显著提升性能。在一般情况下,即使成员变量有默认构造函数,使用初始化列表也可能带来轻微的性能提升,并且代码逻辑更清晰,表明成员变量是如何初始化的。