类成员初始化的首选方式?

时间:2016-03-28 20:28:15

标签: c++11 initialization class-members

class A { public: int x[100]; };

声明A a不会初始化对象(字段x中的垃圾值会看到)。 以下内容将触发初始化:A a{}auto a = A()auto a = A{}

三者中的任何一个是否应该优先考虑?

接下来,让我们将其作为另一个类的成员:

class B { public: A a; };

B的默认构造函数似乎负责a的初始化。 但是,如果使用自定义构造函数,我必须处理它。 以下两个选项有效:

class B { public: A a;  B() : a() { } };

或:

class B { public: A a{};  B() { } };

两者中是否有任何一个首选?

1 个答案:

答案 0 :(得分:3)

初始化

class A { public: int x[100]; };
     

声明A a不会初始化对象(垃圾会看到)   字段中的值x)。

正确A a是在没有初始化程序的情况下定义的,不符合default initialization的任何要求。

  

1)以下内容将触发初始化:

A a{};

是;

  

2)以下内容将触发初始化:

auto a = A();

是;

  

3)以下内容将触发初始化:

auto a = A{}

是;

  • 这是copy initialization,其中使用list initialization {}构建prvalue临时值
  • Copy elision可能并且通常会被用来优化副本并构建A
    • 允许跳过复制/移动构造函数的副作用。
  • 不能删除移动构造函数。例如A(A&&) = delete;
  • 如果删除了复制构造函数,则必须存在移动构造函数。例如A(const A&) = delete; A(A&&) = default;
  • 会警告缩小转换率。
  • 即使删除默认构造函数也能正常工作。例如A() = delete;(如果' A'仍然被视为聚合)
  

三者中的任何一个是否应该优先考虑?

显然,您应该更喜欢A a{}

会员初始化

  

接下来,让我们将其作为另一个类的成员:

class B { public: A a; };
     

B的默认构造函数似乎负责初始化   a

不,这不正确。

  • ' B' 隐式定义的默认构造函数将调用A的默认构造函数,但不会初始化成员。不会触发直接或列表初始化。此示例的语句B b;将调用默认构造函数,但会留下A数组的不确定值。
  

1)但是,如果使用自定义构造函数,我必须处理它。该   以下两个选项有效:

class B { public: A a;  B() : a() { } };

这将有效;

  

2)或:

class B { public: A a{};  B() { } };

这将有效;

显然你应该选择第二种选择。

就我个人而言,我更喜欢在任何地方使用大括号,auto用于std::initializer_list以及构造函数可能将其误认为class B { public: A a{}; }; 的情况:

std::vector

对于std::vector<int> v1(5,10)std::vector<int> v1{5,10}(5,10)构造函数的行为会有所不同。使用{5,10},您可以获得5个元素,每个元素的值为10,但使用std::initializer_list,您会得到两个元素,分别包含5和10,因为如果您使用大括号,则a()是首选。这在Scott Meyers的Effective Modern C ++第7项中得到了很好的解释。

特别针对member initializer lists,可以考虑两种格式:

在成员初始化列表中,幸运的是,没有最烦恼的解析风险。在初始化列表之外,作为一个语句,A a{}将声明一个函数与{{1}},这本来是清楚的。此外,list initialization还可以防止缩小转化次数。

因此,总而言之,这个问题的答案取决于您想要确定的内容,这将决定您选择的形式。对于空初始化器,规则更宽容。