混合内联和构造函数初始化的初始化顺序
Order of initialization with mixed inline and constructor initializations
[这个问题来自this question]
考虑以下程序:
#include <iostream>
struct Foo
{
const size_t size;
int* arr{ create_arr(size) };
Foo(size_t s)
: size{ set_size(s) }
{
}
static int* create_arr(size_t s)
{
std::cout << "Creating array with size " << s << '\n';
return new int[s];
}
static size_t set_size(size_t s)
{
std::cout << "Setting size to " << s << '\n';
return s;
}
};
int main()
{
Foo f(10);
}
arr
的内联初始化取决于 size
的值。但是 size
的值只在构造函数初始化列表中被初始化。
Both GCC and Clang handles it correctly, and will complain if the declaration order of size
and arr
is mirrored. I've also heard that MSVC will do the "right" thing (according to comments in the other question).
我的问题是:这个定义明确吗?
我知道初始化是按声明顺序完成的,但它是否也包括内联初始化?
I know that initialization is done in declaration order, but does it
include inline initialization as well?
是的,必须的,看class.base.init :
13 In a non-delegating constructor, initialization proceeds in the
following order: (13.1) — First, and only for the constructor of the
most derived class (4.5), virtual base classes are initialized in the
order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is the
order of appearance of the base classes in the derived class
base-specifier-list. (13.2) — Then, direct base classes are
initialized in declaration order as they appear in the
base-specifier-list (regardless of the order of the mem-initializers).
(13.3) — Then, non-static data members are initialized in the order
they were declared in the class definition (again regardless of the
order of the mem-initializers). (13.4) — Finally, the
compound-statement of the constructor body is executed. [ Note: The
declaration order is mandated to ensure that base and member sub
虽然这里的标准不是太具体,但应该足够了,因为默认成员初始化器是初始化器。 class 定义中的顺序始终是这里的基础。在初始化方面,这里有一个例外将与标准的许多其他部分极为矛盾。
本节中还有一个附加说明,该标准通过关注销毁来强调:
[ Note: The declaration order is mandated to ensure that base and
member subobjects are destroyed in the reverse order of
initialization. — end note ]
所以这里根本没有更多的解释空间。
是的,定义明确。我将在这里使用 C++20 的 N4860 草案作为参考。
11.10.2 初始化基础和成员 [class.base.init] §9 说(强调我的):
In a non-delegating constructor, if a given potentially constructed subobject is not designated by a meminitializer-
id (including the case where there is no mem-initializer-list because the constructor has no ctorinitializer),
then
(9.1) — if the entity is a non-static data member that has a default member initializer (11.4) and either
(9.1.1) — the constructor’s class is a union (11.5)...
(9.1.2) — the constructor’s class is not a union, and, if the entity is a member of an anonymous union...
(9.2) — otherwise, if the entity is an anonymous union or a variant member (11.5.1), ...
(9.3) — otherwise, the entity is default-initialized (9.4).
这与 11.4 Class 成员一致 [class.mem] §10
A brace-or-equal-initializer shall appear only in the declaration of a data member. (For static data members,
see 11.4.8.2; for non-static data members, see 11.10.2 and 9.4.1). A brace-or-equal-initializer for a non-static
data member specifies a default member initializer for the member...
最后,我们在 11.10.2 Initializing bases and members [class.base.init] §13 说(强调我的):
13 In a non-delegating constructor, initialization proceeds in the following order:
(13.1) — First, and only for the constructor of the most derived class (6.7.2), virtual base classes are initialized in
the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes,
where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list
(regardless of the order of the mem-initializers).
(13.3) — Then, non-static data members are initialized in the order they were declared in the class definition
(again regardless of the order of the mem-initializers).
(13.4) — Finally, the compound-statement of the constructor body is executed.
[Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the
reverse order of initialization. —end note]
我的理解是 class 的成员是按声明顺序初始化的 无论他们是否使用 mem-initializer.如果一个成员没有 mem-initializer 但有一个 brace-or-equal-initializer,它将默认从那个 brace-or-equal-initializer after 初始化之前声明的成员。
因此,如果我正确阅读了 11.4 和 11.2 子条款,则相关代码具有明确定义的行为。
[这个问题来自this question]
考虑以下程序:
#include <iostream>
struct Foo
{
const size_t size;
int* arr{ create_arr(size) };
Foo(size_t s)
: size{ set_size(s) }
{
}
static int* create_arr(size_t s)
{
std::cout << "Creating array with size " << s << '\n';
return new int[s];
}
static size_t set_size(size_t s)
{
std::cout << "Setting size to " << s << '\n';
return s;
}
};
int main()
{
Foo f(10);
}
arr
的内联初始化取决于 size
的值。但是 size
的值只在构造函数初始化列表中被初始化。
Both GCC and Clang handles it correctly, and will complain if the declaration order of size
and arr
is mirrored. I've also heard that MSVC will do the "right" thing (according to comments in the other question).
我的问题是:这个定义明确吗?
我知道初始化是按声明顺序完成的,但它是否也包括内联初始化?
I know that initialization is done in declaration order, but does it include inline initialization as well?
是的,必须的,看class.base.init :
13 In a non-delegating constructor, initialization proceeds in the following order: (13.1) — First, and only for the constructor of the most derived class (4.5), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list. (13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers). (13.3) — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers). (13.4) — Finally, the compound-statement of the constructor body is executed. [ Note: The declaration order is mandated to ensure that base and member sub
虽然这里的标准不是太具体,但应该足够了,因为默认成员初始化器是初始化器。 class 定义中的顺序始终是这里的基础。在初始化方面,这里有一个例外将与标准的许多其他部分极为矛盾。
本节中还有一个附加说明,该标准通过关注销毁来强调:
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]
所以这里根本没有更多的解释空间。
是的,定义明确。我将在这里使用 C++20 的 N4860 草案作为参考。
11.10.2 初始化基础和成员 [class.base.init] §9 说(强调我的):
In a non-delegating constructor, if a given potentially constructed subobject is not designated by a meminitializer- id (including the case where there is no mem-initializer-list because the constructor has no ctorinitializer), then
(9.1) — if the entity is a non-static data member that has a default member initializer (11.4) and either
(9.1.1) — the constructor’s class is a union (11.5)...
(9.1.2) — the constructor’s class is not a union, and, if the entity is a member of an anonymous union... (9.2) — otherwise, if the entity is an anonymous union or a variant member (11.5.1), ...
(9.3) — otherwise, the entity is default-initialized (9.4).
这与 11.4 Class 成员一致 [class.mem] §10
A brace-or-equal-initializer shall appear only in the declaration of a data member. (For static data members, see 11.4.8.2; for non-static data members, see 11.10.2 and 9.4.1). A brace-or-equal-initializer for a non-static data member specifies a default member initializer for the member...
最后,我们在 11.10.2 Initializing bases and members [class.base.init] §13 说(强调我的):
13 In a non-delegating constructor, initialization proceeds in the following order:
(13.1) — First, and only for the constructor of the most derived class (6.7.2), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
(13.3) — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
(13.4) — Finally, the compound-statement of the constructor body is executed.
[Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note]
我的理解是 class 的成员是按声明顺序初始化的 无论他们是否使用 mem-initializer.如果一个成员没有 mem-initializer 但有一个 brace-or-equal-initializer,它将默认从那个 brace-or-equal-initializer after 初始化之前声明的成员。
因此,如果我正确阅读了 11.4 和 11.2 子条款,则相关代码具有明确定义的行为。