Gab*_*les 32 c++ struct initialization
这是一个相关的 C 答案,在 C++ 中不起作用(作为结构的零初始化器):Initializing a struct to 0。提出的解决方案之一是:
myStruct _m1 = {0};
Run Code Online (Sandbox Code Playgroud)
这在 C 中工作正常,但在 C++ 中不起作用。:( :
错误:无法使用“int”类型的右值初始化“myScope::MyStruct”类型的成员子对象。
如何在 C++ 中对结构体进行零初始化?
我的问题不是这个其他问题的重复(Initialization with empty curlybraces),因为这个其他问题不是询问在 C++ 中初始化结构体的各种方法以及为什么 C 方法不起作用,而是它们是询问为什么 C++ 关键字会explicit
破坏他们的初始化技术之一。两个不同的问题。不重复。
Gab*_*les 49
在我们开始之前:
让我指出,围绕此语法的许多混乱是因为在 C 和 C++ 中,您都可以使用该语法将C 样式数组= {0}
的所有成员初始化为零!请参阅此处: https: //en.cppreference.com/w/c/language/array_initialization。所以,这有效:
Run Code Online (Sandbox Code Playgroud)// z has type int[3] and holds all zeroes, as: `{0, 0, 0}` int z[3] = {0};
但是,该语法对于struct 的作用并不相同,它们是与 C 风格数组完全不同的动物。此外,C 和 C++ 之间允许结构初始化的各种技术也有所不同。
更进一步,人们应该知道,从技术上讲,= {0}
仅将数组的第一个0
元素显式初始化为,其余元素会隐式自动初始化为,0
因为它们的值未指定,因此它们得到值初始化(对于非类类型为零初始化;请参阅此处)至0
。
这些来自最新 cppreference.com 社区 wiki ( https://en.cppreference.com/w/c/language/array_initialization ) 的修订示例使这一点更加清晰。特别注意该int y[5] = {1,2,3};
示例没有指定最后两个元素,因此它们隐式默认初始化为 0,并且该int z[4] = {1};
示例仅显式将第一个元素初始化为 1,因此其余所有元素都隐式默认初始化为 0,并且该int w[3] = {0};
示例仅显式地将第一个元素初始化为零,因此其余所有元素都隐式默认初始化为零:
从大括号括起来的列表初始化
当使用大括号括起来的初始化器列表初始化数组时,列表中的第一个初始化器将索引零处的数组元素初始化(除非指定了指示符)(自 C99 起),并且每个后续初始化器不带指示符(自 C99 起)初始化索引处的数组元素,该索引比前一个初始化器初始化的索引大一。
Run Code Online (Sandbox Code Playgroud)// z has type int[3] and holds all zeroes, as: `{0, 0, 0}` int z[3] = {0};
不过,上面的例子同样适用于数组,而这个答案适用于结构。那么,让我们继续吧。
另请参阅我在下面写下此答案后提出的后续问题:Why does notinitializing a C++ struct to = {0}
set all of its member to 0?
回到答案:
我想通了:要让它编译,只需删除零:
int x[] = {1,2,3}; // x has type int[3] and holds 1,2,3
int y[5] = {1,2,3}; // y has type int[5] and holds 1,2,3,0,0
int z[4] = {1}; // z has type int[4] and holds 1,0,0,0
int w[3] = {0}; // w has type int[3] and holds all zeroes
Run Code Online (Sandbox Code Playgroud)
现在可以编译了。但是,我运行了一系列测试来检查eRCaGuy_hello_world存储库中的struct_initialization.cpp文件中的一些内容,并且使用不会将结构的所有元素初始化为零!相反,它将结构初始化为其默认值,称为“值初始化”(请参阅此处的答案)。要运行我的测试并亲自查看,请克隆上面的存储库并运行.= {}
eRCaGuy_hello_world/cpp/struct_initialization_run.sh
假设你有这个结构:
// does NOT work in C++ (but *does* work in C)
myStruct _m1 = {0};
// works in both C and C++!
myStruct _m1 = {};
Run Code Online (Sandbox Code Playgroud)
注意:typedef
上面的内容是我在 C 而不是 C++ 中测试这些东西时遗留下来的(当然,尽管 C 中不允许默认的结构值)。对于 C++,这是首选:
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
Run Code Online (Sandbox Code Playgroud)
因此,如果我不必要地使用它typedef
来定义下面的结构,请忽略它。
无论如何,如果我声明上述结构之一data_t
,然后执行以下操作:
struct data_t
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
};
Run Code Online (Sandbox Code Playgroud)
...输出将是:
data_t d2 = {};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
Run Code Online (Sandbox Code Playgroud)
我什至不确定是否d2.num3
为零,因为它已初始化为零,或者因为它未初始化,而该内存位置恰好包含零。
所发生的情况是将= {}
所有值设置为其默认值,即100
member num1
、-100
membernum2
和150
member 的默认值num4
。num3
我们没有设置显式的默认值,因此它被初始化为零作为其隐式默认值。阅读我的后续问题的这些答案:
当你有
T t{};
或T t = {}
你正在做的事情称为值初始化。在值初始化中,如果对象/成员没有默认构造函数或默认成员初始值设定项,则编译器将回退到零以初始化对象/成员。所以与Run Code Online (Sandbox Code Playgroud)d2.num1 = 100 d2.num2 = -100 d2.num3 = 0 d2.num4 = 150
成员的值按顺序为 100, -100, 0 ,150 ,发生这种情况是
0
因为num3
它没有默认值,并且您没有在 中提供值,{}
因此编译器回退到零初始化num3
。
data_t d3 = {0}
是列表初始化语法,它与诸如 之类的聚合data_t
一起执行聚合初始化:提供的0
值用于初始化第一个成员,其余成员使用相应的默认值进行初始化,如果不存在,则进行值初始化(强调我的,针对 C++14 进行了编辑):如果初始化器子句的数量小于成员的数量或初始化器列表完全为空,则其余成员将由其默认成员初始化器(如果在类定义中提供)进行初始化,否则将根据通常的列表由空列表进行初始化-初始化规则(使用默认构造函数对非类类型和非聚合类执行值初始化,并对聚合执行聚合初始化)。如果引用类型的成员是这些剩余成员之一,则程序格式错误。
值初始化意味着非类类型的零初始化。这
num3
就是为什么没有默认值的member 获取 value 的原因0
。注意:不要与default-initialization混淆,后者根本不初始化非类类型。
data_t d3;
将是default-initialization,并且成员num3
将处于不确定状态。...
正如这里所解释的: https: //en.cppreference.com/w/cpp/language/zero_initialization,您也可以这样做:
data_t d{}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,这段代码:
myStruct _m1{};
Run Code Online (Sandbox Code Playgroud)
...将产生与我上面显示的相同的输出。
即使在将结构设置为= {0}
有效的情况下,例如:
data_t d2{};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
Run Code Online (Sandbox Code Playgroud)
...输出仍然不是我最初预期的,因为它只将第一个值设置为零!(我不明白为什么;由于列表/聚合初始化和值初始化的层次结构(当未设置显式默认值时零初始化);请参阅此处的问题和那里的几个答案):
// Does NOT do what I originally expected! Only sets the FIRST value in the
// struct to zero!
// The rest use default values, which are either 1) the explicit defaults if you
// set them with `= some_num` or whatever in the struct definition, or which are
// 2) in C++ at least, the implicit default values of `0` if you did not set
// explicit defaults.
data_t d3 = {0};
printf("d3.num1 = %i\nd3.num2 = %i\nd3.num3 = %i\nd3.num4 = %i\n\n",
d3.num1, d3.num2, d3.num3, d3.num4);
Run Code Online (Sandbox Code Playgroud)
然而,在 C 风格的数组(不是结构体)上,这些语义工作得很好。请参阅此处的答案(How to将数组的所有成员初始化为相同的值?)。因此,在使用 C++ 时,以下几行都将 C 样式数组的所有元素设置为零:
d3.num1 = 0
d3.num2 = -100
d3.num3 = 0
d3.num4 = 150
Run Code Online (Sandbox Code Playgroud)
因此,经过多次实验,看起来以下几种方法是对结构体 PERIOD 进行零初始化的唯一方法。如果您有不同的看法,请在此发表评论和/或留下您自己的答案。
明确:
// C-style typedef'ed struct
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
// EXPLICITLY set every value to what you want!
data_t d1 = {0, 0, 0, 0};
// OR (using gcc or C++20 only)
data_t d2 = {.num1 = 0, .num2 = 0, .num3 = 0, .num4 = 0};
Run Code Online (Sandbox Code Playgroud)
用于memset()
强制所有字节为零:
data_t d3;
memset(&d3, 0, sizeof(d3));
Run Code Online (Sandbox Code Playgroud)
首先将所有默认值设置为零:
// C-style typedef'ed struct
typedef struct
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
} data_t;
// Set all values to their defaults, which are zero in
// this case
data_t d4 = {};
// OR
data_t d5{}; // same thing as above in C++
// Set the FIRST value only to zero, and all the rest
// to their defaults, which are also zero in this case
data_t d6 = {0};
Run Code Online (Sandbox Code Playgroud)
为 C++ 结构编写构造函数
// 1. Using an initializer list
struct data
{
int num1;
int num2;
int num3;
int num4;
data() :
num1(0),
num2(0),
num3(0),
num4(0) {}
};
data d7; // all values are zero
// OR: 2. manually setting the values inside the constructor
struct data
{
int num1;
int num2;
int num3;
int num4;
data()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d8; // all values are zero
Run Code Online (Sandbox Code Playgroud)
使用没有默认值的结构,并根据它创建对象static
typedef struct
{
int num1;
int num2;
int num3;
int num4;
} data_t;
// `static` forces a default initialization of zero for each
// value when no other default values are set
static data_t d9;
Run Code Online (Sandbox Code Playgroud)
因此,如果您有一个具有非零默认值的结构,并且您想要将所有值归零,则必须明确执行此操作!这里还有一些方法:
// 1. Have a `constexpr` copy of the struct that you use to
// reset other struct objects. Ex:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
};
constexpr data DATA_ALL_ZEROS = {0, 0, 0, 0};
// Now initialize d13 to all zeros using the above `constexpr` struct
// object
data d13 = DATA_ALL_ZEROS;
// OR 2. Use a `zero()` member function to zero the values:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
zero()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d14;
d14.zero();
Run Code Online (Sandbox Code Playgroud)
data_t d{}
、data_t d = {}
和data_t d = {0}
,实际上都没有将结构体的所有成员设置为零!data_t d{}
将所有值设置为结构中定义的默认值。data_t d = {}
还将所有值设置为其默认值。data_t d = {0}
仅将 FIRST 值设置为零,并将所有其他值设置为其默认值。在上述所有情况下,如果未设置显式默认值,则隐式默认值为零 ( 0
)。
因此,如果您希望将特定值设置为默认值,请明确说明!
请注意,我写的上述关键要点似乎与 cppreference.com 上的文档相矛盾,因此它促使我提出下面列出的后续问题,事实证明这对我的理解非常有帮助!
= {0}
其所有成员设置为 0?cpp/run_struct_initialization.sh
leds[0] = {10, 20, 30, 40, 50};
] Arduino Stack Exchange:初始化结构数组[ ] 我最近在 C: 中看到了这个my_struct_t my_struct = {{0}};
。例如,研究它的作用,以及它是否仅在 C 中有效,而在 C++ 中无效。
几周后,2024 年 1 月更新:它似乎是 C 中结构或结构中列表的聚合值初始化。我认为在 C 中它适用于结构或结构中列表,但在 C++ 中它可能只适用于结构中的列表。
归档时间: |
|
查看次数: |
48356 次 |
最近记录: |