初始化列表

内容简介

初始化列表用于在构造函数体执行前初始化成员。它不是简单的语法糖,很多成员必须通过初始化列表初始化。

用法

class Person {
public:
    Person(int a, int b, int c)
        : a_(a), b_(b), c_(c)
    {
    }
 
private:
    int a_;
    int b_;
    int c_;
};

为什么不用构造函数体内赋值

构造函数体内写法:

Person::Person(int a, int b, int c)
{
    a_ = a;
    b_ = b;
    c_ = c;
}

这不是初始化,而是先默认初始化成员,再赋值。对于简单 int 差异不明显,但对于 const、引用、无默认构造的成员对象,必须用初始化列表。

必须用初始化列表的场景

const 成员

class Config {
public:
    explicit Config(int port) : port_(port) {}
 
private:
    const int port_;
};

引用成员

class Holder {
public:
    explicit Holder(int& value) : value_(value) {}
 
private:
    int& value_;
};

成员对象没有默认构造函数

class Phone {
public:
    explicit Phone(std::string name) : name_(std::move(name)) {}
 
private:
    std::string name_;
};
 
class Person {
public:
    Person(std::string name, std::string phone)
        : name_(std::move(name)), phone_(std::move(phone))
    {
    }
 
private:
    std::string name_;
    Phone phone_;
};

初始化顺序

成员初始化顺序由成员在类中的声明顺序决定,不由初始化列表书写顺序决定。

class Demo {
public:
    Demo() : b_(1), a_(b_) {}
 
private:
    int a_;
    int b_;
};

这里 a_ 会先初始化,因为它先声明。不要依赖初始化列表顺序制造隐式关系。

最佳代码实践

  • 构造函数优先使用初始化列表。
  • 初始化列表顺序和成员声明顺序保持一致。
  • 构造函数参数和成员同名时,可用结尾下划线区分成员变量。
  • 成员对象初始化失败时,已构造完成的成员会自动析构。

错误用法

Person::Person() : a_(1), b_(2), c_(3);

问题:这是声明,不是构造函数定义。构造函数需要函数体:

Person::Person() : a_(1), b_(2), c_(3)
{
}

注意事项

学习路径