C++ 默认变量值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6032638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Default variable value
提问by CaptainProg
If I don't assign a value to a variable when I declare it, does it default to zero or just whatever was previously in the memory?
如果我在声明一个变量时没有给它赋值,它是默认为零还是只是之前内存中的任何值?
e.g.
例如
float x;
采纳答案by Alok Save
A declared variable can be Zero Initialized, Value Initializedor Default Initialized.
声明的变量可以是零初始化、值初始化或默认初始化。
The C++03 Standard 8.5/5 aptly defines each:
C++03 标准 8.5/5 恰当地定义了每个:
To zero-initializean object of type T means:
对T 类型的对象进行零初始化意味着:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject
is zero-initialized;
— if T is a union type, the object's first named data member is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
— 如果 T 是标量类型 (3.9),则对象设置为转换为 T 的 0(零)值;
— 如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象
都是零初始化的;
— 如果 T 是联合类型,则对象的第一个命名数据成员为零初始化;
— 如果 T 是数组类型,则每个元素都初始化为零;
— 如果 T 是引用类型,则不执行初始化。
To default-initializean object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.
到默认初始化的类型T的装置的对象:
-如果T是一个非POD类型(第9节),T的默认构造函数被调用(并形成不良的初始化如果T没有可访问的缺省的构造);
— 如果 T 是数组类型,则每个元素都是默认初始化的;
— 否则,对象是零初始化的。
To value-initializean object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default
constructor for T is called (and the initialization is ill-formed if T has no accessible
default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static
data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
到值初始化的类型T的装置的对象:
-如果T是一个类型(第9节)与用户声明的构造(12.1),然后对T中的默认构造函数被调用(以及初始化是形成不良的如果T没有可访问的默认构造函数);
— 如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都进行了值初始化;
— 如果 T 是数组类型,则每个元素都进行了值初始化;
— 否则,对象是零初始化的
For example:
例如:
#include<iostream>
using namespace std;
static int a; //Zero Initialized
int b; //Zero Initialized
int main()
{
int i; //Undefined Behavior, Might be Initialized to anything
static int j; //Zero Initialized
cout<<"\nLocal Uninitialized int variable [i]"<<i<<"\n";
cout<<"\nLocal Uninitialized Static int variable [j]"<<j<<"\n";
cout<<"\nGlobal Uninitialized Static int variable [a]"<<a<<"\n";
cout<<"\nGlobal Uninitialized int variable [b]"<<b<<"\n";
return 0;
}
You will notice The results for variable i
will be different on different compilers. Such local uninitialized variables SHOULD NEVERbe used. In fact, if you turn on strict compiler warnings, the compiler shall report an error about it. Here's how codepad reports it an error.
您会注意到变量的结果i
在不同的编译器上会有所不同。这种局部未初始化的变量不应该被使用。事实上,如果你打开了严格的编译器警告,编译器会报告一个错误。以下是键盘如何报告错误。
cc1plus: warnings being treated as errors
In function 'int main()':
Line 11: warning: 'i' is used uninitialized in this function
Edit: As rightfully pointed out by @Kirill V. Lyadvinsky in the comments, SHOULD NEVERis a rather very strong word, and there can be perfectly valid code which might use uninitialized variables as he points out an example in his comment. So, I should probably say:
You should never be using uninitialized variables unless you know exactly what you are doing.
编辑:正如@Kirill V. Lyadvinsky 在评论中正确指出的那样,SHOULD NEVER是一个非常强的词,并且可以有完全有效的代码可能使用未初始化的变量,因为他在评论中指出了一个例子。所以,我可能应该说:
除非您确切地知道自己在做什么,否则永远不应该使用未初始化的变量。
回答by Kirill V. Lyadvinsky
It depends. If this is a local variable (an object with automatic storage duration) it will be uninitialized, if it is a global variable (an object with static storage duration) it will be zero initialized. Check also this answer.
这取决于。如果这是一个局部变量(具有自动存储持续时间的对象),它将是未初始化的,如果它是一个全局变量(具有静态存储持续时间的对象),它将被零初始化。也检查这个答案。
回答by James Kanze
It depends on the lifetime of the variable. Variables with static lifetime are always zero-initialized before program start-up: zero-initialization for basic types, enum
s and pointers is the same as if you'd assigned 0
, appropriately converted to the type, to it. This occurs even if the variable has a constructor, before the constructor is called.
这取决于变量的生命周期。具有静态生命周期的变量在程序启动之前总是零初始化:基本类型、enum
s 和指针的零初始化与您将 分配0
给它并适当转换为类型相同。即使变量具有构造函数,在调用构造函数之前也会发生这种情况。
回答by kusma
This depends on where you declare it. Variables in the global scope are initialized with 0, and stack-variables are undefined.
这取决于你在哪里声明它。全局范围内的变量初始化为 0,堆栈变量未定义。
回答by Claudiu
I think it's undefined. I think some compilers, when compiling in debug mode, initialize it to zero. But it's also ok to have it be whatever was already there in memory. Basically - don't rely on either behavior.
我认为它是未定义的。我认为一些编译器在调试模式下编译时,将其初始化为零。但也可以让它成为内存中已经存在的任何东西。基本上 - 不要依赖任何一种行为。
UPDATE: As per the comments - global variables will be zero-initialized. Local variables will be whatever.
更新:根据评论 - 全局变量将被零初始化。局部变量将是任何东西。
To answer your second question:
回答你的第二个问题:
Thanks - following on from this then, is there a shortcut to assign zero to all of the following?: float x1, x2, x3, x4, x5, y1, y2, y3, y4, y5
谢谢 - 从这里开始,是否有将零分配给以下所有内容的快捷方式?: float x1, x2, x3, x4, x5, y1, y2, y3, y4, y5
You could do
你可以做
float x[5] = {0,0,0,0,0}; float y[5] = {0,0,0,0,0};
and use x[0]
instead of x1
.
并使用x[0]
代替x1
.
回答by giacomo-b
Since the current top-answer was written in 2011 and only refers to C++03, I am providing an updated answer to keep into account changes made after C++11. Note that I am stripping any information that only held true until C++03 or C++11 and unnecessary notes that can be seen in the original sources. I am quoting the original specifications as much as I can, in order to avoid unnecessary reformulation which may lead to inexact information. Please consult the original sources I am providing if you are interested in diving deeper into a certain topic. Also, be warned that I am mainly focusing on rules regarding * Default initialization * Undefined behavior * Zero-initialization Since it seems to me that these are the most important aspects needed to understand how a variable behaves "by default", as the question is asking.
由于当前的最佳答案是在 2011 年编写的,并且仅涉及 C++03,因此我提供了一个更新的答案,以考虑 C++11 之后所做的更改。请注意,我正在剥离仅在 C++03 或 C++11 之前有效的任何信息以及可以在原始来源中看到的不必要的注释。我尽可能多地引用原始规格,以避免不必要的重新表述,这可能会导致信息不准确。如果您有兴趣深入研究某个主题,请查阅我提供的原始资料。另外,请注意,我主要关注关于 * 默认初始化 * 未定义行为 * 零初始化的规则 因为在我看来,这些是理解变量“默认”如何表现所需的最重要方面,因为问题是问。
Default initialization is performed in some cases:
- when a variable with automatic, static, or thread-local storage duration is declared with no initializer;
- when an object with dynamic storage duration is created by a new-expression with no initializer;
- when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.
- 当没有初始化程序声明具有自动、静态或线程本地存储持续时间的变量时;
- 当具有动态存储期的对象由没有初始化器的 new 表达式创建时;
- 当构造函数初始值设定项列表中未提及基类或非静态数据成员并且调用该构造函数时。
and the effects of this default initialization are:
这个默认初始化的效果是:
if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
if T is an array type, every element of the array is default-initialized;
- otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.
如果 T 是非 POD(直到 C++11)类类型,则考虑构造函数并针对空参数列表进行重载决议。调用选定的构造函数(默认构造函数之一)为新对象提供初始值;
如果 T 是数组类型,则数组的每个元素都是默认初始化的;
- 否则,什么都不做:具有自动存储持续时间的对象(及其子对象)被初始化为不确定的值。
Meaning that if the uninitialized variable is a local (say, an int
only present in a function's scope), its value is indeterminate (undefined behavior). cppreference strongly discourages the usage of uninitialized variables.
这意味着如果未初始化的变量是局部变量(例如,int
仅存在于函数作用域中),则其值是不确定的(未定义行为)。cppreference 强烈反对使用未初始化的变量。
As a side note, even though most modern compilers will issue an error (at compile-time) if they detect that an uninitialized variable is being used, they usually fail to do so in cases were you are "tricking" them to think you may be initializing the variable somehow, such as in:
作为旁注,即使大多数现代编译器在检测到正在使用未初始化的变量时都会发出错误(在编译时),但如果您“欺骗”他们认为您可能以某种方式初始化变量,例如:
int main()
{
int myVariable;
myFunction(myVariable); // does not change the variable
cout << myVariable << endl; // compilers might think it is now initialized
}
Starting from C++14, the following holds (note that std::byte
was introduced with C++17):
从 C++14 开始,以下内容成立(注意std::byte
是在 C++17 中引入的):
Use of an indeterminate value obtained by default-initializing a non-class variable of any type is undefined behavior (in particular, it may be a trap representation), except in the following cases:
if an indeterminate value of type
unsigned char
orstd::byte
is assigned to another variable of type (possibly cv-qualified)unsigned char
orstd::byte
(the value of the variable becomes indeterminate, but the behavior is not undefined);if an indeterminate value of type
unsigned char
orstd::byte
is used to initialize another variable of type (possibly cv-qualified)unsigned char
orstd::byte
;if an indeterminate value of type unsigned char or std::byte (since C++17) results from
- the second or third operand of a conditional expression,
- the right operand of the comma operator,
- the operand of a cast or conversion to (possibly cv-qualified)
unsigned char
orstd::byte
,- a discarded-value expression.
使用通过默认初始化任何类型的非类变量获得的不确定值是未定义行为(特别是,它可能是陷阱表示),但以下情况除外:
如果类型的不确定值
unsigned char
orstd::byte
被分配给另一个类型的变量(可能是 cv 限定的)unsigned char
或std::byte
(变量的值变得不确定,但行为不是未定义的);如果类型的不确定值
unsigned char
orstd::byte
用于初始化另一个类型的变量(可能是 cv 限定的)unsigned char
或std::byte
;如果 unsigned char 或 std::byte (C++17 起)类型的不确定值来自
- 条件表达式的第二个或第三个操作数,
- 逗号运算符的右操作数,
- 强制转换或转换为(可能是 cv 限定的)
unsigned char
或的操作数std::byte
,- 丢弃值表达式。
Additional details about the default initialization of variables and their behavior can be found here.
可以在此处找到有关变量默认初始化及其行为的其他详细信息。
To dive deeper into indeterminate values, in 2014 the following changes were made (as Shafik Yaghmour pointed out herewith additional useful resources):
为了更深入地研究不确定值,2014 年进行了以下更改(正如Shafik Yaghmour 在此处指出的其他有用资源):
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [Note: Objects with static or thread storage duration are zero-initialized]
如果没有为对象指定初始化程序,则该对象是默认初始化的;如果不进行初始化,具有自动或动态存储持续时间的对象具有不确定的值。[注意:具有静态或线程存储持续时间的对象是零初始化的]
to:
到:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. [Note: Objects with static or thread storage duration are zero-initialized] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
If an indeterminate value of unsigned narrow character type is produced by the evaluation of:
the second or third operand of a conditional expression (5.16 [expr.cond]),
the right operand of a comma,
the operand of a cast or conversion to an unsigned narrow character type, or
a discarded-value expression,
then the result of the operation is an indeterminate value.
If an indeterminate value of unsigned narrow character type is produced by the evaluation of the right operand of a simple assignment operator whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.
If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.
如果没有为对象指定初始化程序,则该对象是默认初始化的。获取自动或动态存储期限的对象的存储时,该对象具有不确定值,如果未对该对象进行初始化,则该对象将保留不确定值,直到该值被替换。[注意:具有静态或线程存储持续时间的对象是零初始化的] 如果评估产生不确定值,则行为未定义,但以下情况除外:
如果无符号窄字符类型的不确定值是通过评估产生的:
条件表达式 (5.16 [expr.cond]) 的第二个或第三个操作数,
逗号的右操作数,
强制转换或转换为无符号窄字符类型的操作数,或
丢弃值表达式,
那么操作的结果是一个不确定的值。
如果通过对第一个操作数是无符号窄字符类型的左值的简单赋值运算符的右操作数求值产生了无符号窄字符类型的不确定值,则不确定值将替换左操作数引用的对象的值.
如果在初始化无符号窄字符类型的对象时通过对初始化表达式的求值产生无符号窄字符类型 (3.9.1 [basic.fundamental]) 的不确定值,则该对象将被初始化为不确定值。
Finally, there is the subject of zero-initializationwhich is performed in the following situations:
最后,还有在以下情况下执行的零初始化主题:
For every named variable with static or thread-local storage duration that is not subject to constant initialization (since C++14), before any other initialization.
As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.
When an array of any character type is initialized with a string literal that is too short, the remainder of the array is zero-initialized.
The effects of zero initialization are:
If T is a scalar type, the object's initial value is the integral constant zero explicitly converted to T.
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
If T is a union type, the first non-static named data member is zero-initialized and all padding is initialized to zero bits.
If T is array type, each element is zero-initialized
If T is reference type, nothing is done.
对于每个具有静态或线程本地存储持续时间且不受常量初始化(自 C++14 起)的命名变量,在任何其他初始化之前。
作为非类类型和没有构造函数的值初始化类类型成员的值初始化序列的一部分,包括未提供初始化器的聚合元素的值初始化。
当使用太短的字符串文字初始化任何字符类型的数组时,数组的其余部分将被零初始化。
零初始化的效果是:
如果 T 是标量类型,则对象的初始值是显式转换为 T 的整数常量零。
如果 T 是非联合类类型,则所有基类和非静态数据成员都初始化为零,并且所有填充都初始化为零位。构造函数(如果有)将被忽略。
如果 T 是联合类型,则第一个非静态命名数据成员被零初始化,所有填充都被初始化为零位。
如果 T 是数组类型,则每个元素都初始化为零
如果 T 是引用类型,则什么都不做。
Following are some examples:
以下是一些示例:
#include <iostream>
#include <string>
struct Coordinates {
float x, y;
};
class WithDefaultConstructor {
std::string s;
}
class WithCustomConstructor {
int a, b;
public:
WithCustomConstructor() : a(2) {}
}
int main()
{
int a; // Indeterminate value (non-class)
int& b; // Error
std::string myString; // Zero-initialized to indeterminate value
// but then default-initialized to ""
// (class, calls default constructor)
double coordsArray[2]; // Both will be 0.0 (zero-initialization)
Coordinates* pCoords; // Zero-initialized to nullptr
Coordinates coords = Coordinates();
// x: 0.0
// y: 0.0
std::cout << "x: " << coords.x << '\n'
"y: " << coords.y << std::endl;
std::cout << a.a << a.b << a.c << '\n';
WithDefaultConstructor wdc; // Since no constructor is provided,
// calls the default constructor
WithCustomConstructor wcs; // Calls the provided constructor
// a is initialized, while b is
// default-initialized to an indeterminate value
}
回答by R.. GitHub STOP HELPING ICE
Using the value of any variable prior to initialization (note that static-storage-duration objects are always initialized, so this only applies to automatic storage duration) results in undefined behavior. This is very different from containing 0 as the initial value or containing a random value. UB means it's possible that anythingcould happen. On implementations with trap bits it might crash your program or generate a signal. It's also possible that multiple reads result in differentunpredictable values, among any other imaginable (or unimaginable) behavior. Simply do not use the value of uninitialized variables.
在初始化之前使用任何变量的值(注意 static-storage-duration 对象总是被初始化,所以这仅适用于自动存储持续时间)导致未定义行为。这与包含 0 作为初始值或包含随机值非常不同。UB 意味着任何事情都有可能发生。在带有陷阱位的实现中,它可能会使您的程序崩溃或生成一个信号。多次读取也可能导致不同的不可预测值,以及任何其他可以想象(或无法想象)的行为。根本就不要使用未初始化变量的值。
Note:The following was edited based on comments:
注意:以下内容是根据评论编辑的:
Note that code like this is invalid unless you can assure that the type foo_t
does not have padding bits:
请注意,这样的代码是无效的,除非您可以确保该类型foo_t
没有填充位:
foo_t x;
int i;
for (i=0; i<N; i++) x = (x<<1) | get_bit();
Even though the intent is that the "random value" initially in x
gets discarded before the loop ends, the program may invoke UB as soon as it accesses x
to perform the operation x<<1
on the first iteration, and thus the entire program output is invalidated.
即使意图是x
在循环结束之前最初 in 的“随机值”被丢弃,但程序可能会在访问后立即调用 UBx
以执行x<<1
第一次迭代的操作,因此整个程序输出无效。
回答by Ephphatha
It can be compiler specific but generally release builds don't initialise variables to any particular value, so you get whatever is left in memory. Certain magic numbers are used in debug builds by some compilers to mark specific areas of memory however.
它可以是特定于编译器的,但通常发布版本不会将变量初始化为任何特定值,因此您可以获得内存中剩余的任何内容。然而,某些编译器在调试版本中使用某些幻数来标记内存的特定区域。
回答by matzahboy
C++ does not instantiate variables. The value of x is whatever happened to be in the memory at the time. Never assume anything about its initial value.
C++ 不实例化变量。x 的值是当时内存中发生的任何事情。永远不要对它的初始值做任何假设。