Wikipedia:Reference desk/Archives/Computing/2024 June 1
Appearance
Computing desk | ||
---|---|---|
< May 31 | << May | June | Jul >> | June 2 > |
Welcome to the Wikipedia Computing Reference Desk Archives |
---|
The page you are currently viewing is a transcluded archive page. While you can leave answers for any questions shown below, please ask new questions on one of the current reference desk pages. |
June 1
[edit]C++ array initialization
[edit]Let's say I allocate a new array
std::array<int,10> *x = new std::array<int,10>;
Considerable head scratching at cppreference.com doesn't tell me whether this array's elements are guaranteed to be initialized to 0. Experimentally they do seem to be, but that could be accidental. In C, of course, int x[10]; makes an array that is uninitialized. Does anyone know? Thanks. 2601:644:8501:AAF0:0:0:0:1ECE (talk) 05:14, 1 June 2024 (UTC)
- Cplusplus.com says
By default, regular arrays of local scope (for example, those declared within a function) are left uninitialized. This means that none of its elements are set to any particular value
. I don't know what happens in a global scope. ―Panamitsu (talk) 06:33, 1 June 2024 (UTC)- In C, a global array is initialized to zero. (Reference: K&R, or the latest C standard.) I think C++ works the same way: this page from learncpp.com says "Global variables have static duration" and, later, "Unlike local variables, which are uninitialized by default, variables with static duration are zero-initialized by default." This is not very official C++ reference, but has the advantage of actually telling us the answer. And our compatibility of C and C++ article says various things about arrays, but nothing to contradict that the languages work the same in this respect. Card Zero (talk) 07:44, 1 June 2024 (UTC)
- A std::array is not a C-style array. It acts similarly in many ways but has some differences.The std::array constructor follows the rules of aggregate initialization. But if there is no initializer list (in braces), default initialization is used. The std::array constructor reference linked above says "
note that default initialization may result in indeterminate values for non-class T
", and the default initialization reference linked above clarifies that POD types ("plain old data", like int) are uninitialized by default initialization. So for a std::array<T> created without an initialization list, the elements are uninitialized if T is a POD type. If T is a non-POD class, the elements would be initialized with their default constructor. CodeTalker (talk) 05:53, 2 June 2024 (UTC)- But are you disagreeing, or agreeing? We've all agreed the array would be uninitialized if it has local scope. But do you think an int array with global scope (or "static duration" perhaps more relevantly), with default initialization, is uninitialized? Your links led me to zero initialization, but I still don't see a definitive answer on this site. Presumably it is telling us, in its way.
Zero-initialization is performed in the following situations: 1) For every named variable with static or thread-local(since C++11) storage duration that is not subject to constant initialization, before any other initialization.
- Maybe that means global arrays are initialized to zero, but due to uncertainties about what very formally specified thing in the reference relates to what familiar thing in practice, I can't be sure. Is a global array a variable? Does it have static storage? Fairly sure of the latter, less certain of the former.
- Perhaps you weren't disagreeing, but just elaborating: we have the new wrinkle that uninitialized non-POD types get a default initialization, even at local scope. Card Zero (talk) 08:22, 2 June 2024 (UTC)
- As I read it, the elements are not guaranteed to be initialized. For reference, I'm using final C++23 draft; the numbers in parentheses are the relevant locations in the draft.
- First off, only the pointer has static storage. The array has dynamic storage, having been created by a new-expression (7.6.2.8 (9)). What happens from there is, well, complicated.
- An allocation function may be called to obtain storage (7.6.2.8 (11-13)); if so, the state of the memory thus returned is unspecified (6.7.5.5.2 (2)).
- Now, the expression has no new-initializer, so the result is default-initialized (7.6.2.8 (23.1)).
- Default-initialization means that the best applicable constructor for the initializer
()
(chosen via overload resolution) is called with an empty argument list to initialize the class (9.4.1 (7.1)). - The
array
class is an aggregate, and uses the implicitly-declared default constructor (24.3.7.2 (1)). - This performs whatever initializations that would be performed by a user-written default constructor with no ctor-initializer and an empty compound-statement (basically, a constructor that doesn't specify anything) (11.4.5.2 (4)).
- Not actually knowing precisely what the data members contained are or how they are specified, we are stuck here. There is nothing preventing an implementation from, for instance, storing the data in an array specified with a default member initializer (see 11.9.3 (9.1)) of
{142857, -32768}
. IF one assumes that the class holds an array of 10int
s with no initializer specified (which seems more likely), that array is itself default-initialized (11.9.3 (9.3)); each element thereof is then also default-initialized (9.4.1 (7.2)). For anint
, default-initialization performs no initialization (9.4.1 (7.3)), and we are left with whatever was in the memory we were allocated. - BentSm (talk) 14:01, 2 June 2024 (UTC)
- There are many cases: heap/local/static, POD/non-POD, and created with or without an initializer. The OP was asking about a std::array<int> (POD) on the heap with no initializer. Such a variable is not guaranteed to be zero-initialized. The same is true if local rather than heap but a static would be zero-initialized. In all these cases, non-PODs would be initialized
by the class's default constructor. Heap variables may be default initialized if no initializer is given (uninitialized if POD or default constructed if non-POD) as in the OP's example, or value initialized if given an empty initializer (zero if POD or default constructed if non-POD).So, to enumerate the cases:
BTW, the "experiment" by which the OP found their array to be set to zero would be better done by deliberately unzeroing the heap first, by something like
// --- static; no initializer
static std::array<int,10> a; // initialized to 0
static std::array<MyClass,10> a; // initialized by MyClass::MyClass()
// --- static; empty initializer (same as previous case)
static std::array<int,10> a{}; // initialized to 0
static std::array<MyClass,10> a{}; // initialized by MyClass::MyClass()
// --- local; no initializer
std::array<int,10> a; // uninitialized
std::array<MyClass,10> a; // initialized by MyClass::MyClass()
// --- local; empty initializer
std::array<int,10> a{}; // initialized to 0
std::array<MyClass,10> a{}; // initialized by MyClass::MyClass()
// --- heap; no initializer
std::array<int,10> *a = new std::array<int,10>; // default initialized (uninitialized)
std::array<MyClass,10> *a = new std::array<MyClass,10>; // default initialized: initialized by MyClass::MyClass();
// --- heap; empty initializer
std::array<int,10> *a = new std::array<int,10>(); // value initialized (set to zero)
std::array<MyClass,10> *a = new std::array<MyClass,10>(); // value initialized: also initialized by MyClass::MyClass();
std::array<int,100> *z = new std::array<int,100>;
for (int i = 0; i < 100; ++i) (*z)[i] = 0xffffffff;
delete z;
This is not definitive but it makes it more likely that the next thing allocated from the heap doesn't use fresh system-allocated memory, which might indeed be all zeros. CodeTalker (talk) 17:37, 2 June 2024 (UTC)
- There are many cases: heap/local/static, POD/non-POD, and created with or without an initializer. The OP was asking about a std::array<int> (POD) on the heap with no initializer. Such a variable is not guaranteed to be zero-initialized. The same is true if local rather than heap but a static would be zero-initialized. In all these cases, non-PODs would be initialized
- A std::array is not a C-style array. It acts similarly in many ways but has some differences.The std::array constructor follows the rules of aggregate initialization. But if there is no initializer list (in braces), default initialization is used. The std::array constructor reference linked above says "
- In C, a global array is initialized to zero. (Reference: K&R, or the latest C standard.) I think C++ works the same way: this page from learncpp.com says "Global variables have static duration" and, later, "Unlike local variables, which are uninitialized by default, variables with static duration are zero-initialized by default." This is not very official C++ reference, but has the advantage of actually telling us the answer. And our compatibility of C and C++ article says various things about arrays, but nothing to contradict that the languages work the same in this respect. Card Zero (talk) 07:44, 1 June 2024 (UTC)