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() { } };
是否应该选择两者中的任何一个?
最佳答案
初始化
正确的A a
是在没有初始化程序的情况下定义的,并且不满足default initialization的任何要求。
是的;
a{}
执行list initialization,其中{}
为空,则A
是聚合的,则可能为aggregate initialization。 A() = delete;
(如果仍然将“A”视为集合)是的;
()
构建的,如果
()
为空,则A
。A(A&&) = delete;
A(const A&) = delete; A(A&&) = default;
是的;
{}
构建的,如果
{}
为空,则A
是聚合,则A
。A(A&&) = delete;
A(const A&) = delete; A(A&&) = default;
A() = delete;
(如果仍然将“A”视为集合)显然,您应该更喜欢
A a{}
。成员初始化
不,这是不正确的。
A
的默认构造函数,但不会初始化成员。没有直接或列表初始化将被触发。此示例的语句B b;
将调用默认构造函数,但保留A
数组的不确定值。 这将起作用;
: a()
是constructor initializer,而a()
是成员初始化程序,是member initializer list的一部分。 ()
;如果()
为空,则使用value initialization。 这将起作用;
a
现在有一个non-static data member initializer,如果您使用聚合初始化并且编译器为not fully C++14 compliant,则可能需要构造函数对其进行初始化。 {}
,其中{}
为空,则A
是一个聚合,则aggregate initialization可能会变成some exceptions。 a
是唯一成员,则不必定义默认构造函数,并且将隐式定义默认构造函数。 显然,您应该更喜欢第二种选择。
就个人而言,我更喜欢在任何地方使用花括号,member initializer lists用作
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}
,您将获得两个元素,分别包含5和10,因为如果使用花括号,则std::initializer_list
是首选。这在Scott Meyers的《 Effective Modern C++》的第7条中有很好的解释。特别是对于Direct initialization,可以考虑两种格式:
a()
,如果()
为空,则变为List initialization。 a{}
,如果{}
为空,它也将变成list initialization。 幸运的是,在成员初始化器列表中,没有最烦人的解析风险。在初始化程序列表之外,作为自己的一条语句,
A a()
应该声明了一个函数,而A a{}
已经清楚了。另外,ojit_a的好处是可以防止转换变窄。因此,总而言之,此问题的答案是它取决于您要确定的内容,并且将确定您选择的形式。对于空的初始值设定项,规则更为宽容。
关于c++11 - 类成员初始化的首选方式?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36270612/