How to initialise memory with new operator in C++?
Asked Answered
H

10

210

I'm just beginning to get into C++ and I want to pick up some good habits. If I have just allocated an array of type int with the new operator, how can I initialise them all to 0 without looping through them all myself? Should I just use memset? Is there a “C++” way to do it?

Haworth answered 5/2, 2010 at 0:6 Comment(5)
If you want to pickup a good C++ habit, then avoid using arrays directly and use vector instead. Vector will initialize all the items regardless of the type, and then you don't need to remember to call the delete[] operator.Stevana
@brianegge: What if I need to pass an array to an external C function, can I just give it the vector?Haworth
You can pass &vector[0].Redoubtable
Of course, when you pass arrays to C functions, you typically have to specify the pointer to the first element, &vector[0] as @Redoubtable said, and the size of the array, provided in this case by vector.size().Yarn
Related (asks for non-array types): #7547120Expiratory
G
467

It's a surprisingly little-known feature of C++ (as evidenced by the fact that no-one has given this as an answer yet), but it actually has special syntax for value-initializing an array:

new int[10]();

Note that you must use the empty parentheses — you cannot, for example, use (0) or anything else (which is why this is only useful for value initialization).

This is explicitly permitted by ISO C++03 5.3.4[expr.new]/15, which says:

A new-expression that creates an object of type T initializes that object as follows:

...

  • If the new-initializer is of the form (), the item is value-initialized (8.5);

and does not restrict the types for which this is allowed, whereas the (expression-list) form is explicitly restricted by further rules in the same section such that it does not allow array types.

Gremlin answered 5/2, 2010 at 0:57 Comment(6)
While I agree that this is little-known, I can't (entirely) agree that it's really very surprising -- it was added in C++ 03, which most people seem to have nearly ignored (since this was one of the few new things it did add).Costanzo
@Jerry: I must admit that I didn't knew yet (probably because when I got to reading the standard, it was C++03 already). That said, it's remarkable that all implementations I know of support this (I guess it's because it's so trivial to implement).Gremlin
Yes, it is pretty trivial to implement. As far as being new, all "value initialization" was new in C++ 03.Costanzo
In C++11 you can use uniform initializtion as well: new int[10] {}. You can also provide values to initialize with: new int[10] {1,2,3}Purplish
Please don't confuse default-initialized with value-initialized: They are both clearly defined in the standard and are different initializations.Urbai
Also see Are () and {} always equivalent when used for initialization with "new"? and What do the following phrases mean in C++: zero-, default- and value-initialization?Catawba
S
27

There is number of methods to allocate an array of intrinsic type and all of these method are correct, though which one to choose, depends...

Manual initialisation of all elements in loop

int* p = new int[10];
for (int i = 0; i < 10; i++)
    p[i] = 0;

Using std::memset function from <cstring>

int* p = new int[10];
std::memset(p, 0, sizeof *p * 10);

Using std::fill_n algorithm from <algorithm>

int* p = new int[10];
std::fill_n(p, 10, 0);

Using std::vector container

std::vector<int> v(10); // elements zero'ed

If C++11 is available, using initializer list features

int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime
Simpleminded answered 5/2, 2010 at 0:42 Comment(4)
should be vector<int> If you added p= new int[10]() you had a complete list.Bothnia
@mloskot, in the first case where you have initialized an array using "new", how pass by reference will happen? If I used int array[SIZE] ={1,2,3,4,5,6,7}; notation, I can use void rotateArray(int (& input)[SIZE], unsigned int k); would be my function declaration, what would be when using the first convention? any suggestion?Showker
I am afraid the example with std::memset is wrong - you pass 10, it seems to expect number of bytes - see en.cppreference.com/w/cpp/string/byte/memset. (I think this nicely shows why should one avoid such low-level construct when possible.)Autocatalysis
@Autocatalysis Great catch! Fixed. This seems to be a candidate for a decade old bug :-) Yes, I agree with your comment.Simpleminded
G
26

Assuming that you really do want an array and not a std::vector, the "C++ way" would be this

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable

std::fill_n(array, n, 0); 

But be aware that under the hood this is still actually just a loop that assigns each element to 0 (there's really not another way to do it, barring a special architecture with hardware-level support).

Garret answered 5/2, 2010 at 0:9 Comment(4)
I don't mind if the loop is implemented underneath a function, I just wanted to know whether or not I had to implement such a loop myself. Thanks for the tip.Haworth
You might be surprised. I was. On my STL (both GCC and Dinkumware), std::copy actually turns into a memcpy if it detects it is being called with built in types. I wouldn't be surprised if std::fill_n used memset.Esch
Nope. Use 'Value-Initialization' to set all members to 0.Baily
int * array = new int[n]()Ottinger
C
23

Possible ways of initializing the plain dyanmic array. Choose the one as per your requirement.

int* x = new int[5];          // gv gv gv gv gv (gv - garbage value)
int* x = new int[5]();        // 0  0  0  0  0 
int* x = new int[5]{};        // 0  0  0  0  0  (Modern C++)
int* x = new int[5]{1,2,3};   // 1  2  3  0  0  (Modern C++)
Choreography answered 14/6, 2021 at 9:0 Comment(0)
B
8

If the memory you are allocating is a class with a constructor that does something useful, the operator new will call that constructor and leave your object initialized.

But if you're allocating a POD or something that doesn't have a constructor that initializes the object's state, then you cannot allocate memory and initialize that memory with operator new in one operation. However, you have several options:

  1. Use a stack variable instead. You can allocate and default-initialize in one step, like this:

     int vals[100] = {0}; // first element is a matter of style
    
  2. use memset(). Note that if the object you are allocating is not a POD, memsetting it is a bad idea. One specific example is if you memset a class that has virtual functions, you will blow away the vtable and leave your object in an unusable state.

  3. Many operating systems have calls that do what you want - allocate on a heap and initialize the data to something. A Windows example would be VirtualAlloc().

  4. This is usually the best option. Avoid having to manage the memory yourself at all. You can use STL containers to do just about anything you would do with raw memory, including allocating and initializing all in one fell swoop:

     std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
    
Buchenwald answered 5/2, 2010 at 0:14 Comment(0)
D
7

Yes there is:

std::vector<int> vec(SIZE, 0);

Use a vector instead of a dynamically allocated array. Benefits include not having to bother with explicitely deleting the array (it is deleted when the vector goes out of scope) and also that the memory is automatically deleted even if there is an exception thrown.

Edit: To avoid further drive-by downvotes from people that do not bother to read the comments below, I should make it more clear that this answer does not say that vector is always the right answer. But it sure is a more C++ way than "manually" making sure to delete an array.

Now with C++11, there is also std::array that models a constant size array (vs vector that is able to grow). There is also std::unique_ptr that manages a dynamically allocated array (that can be combined with initialization as answered in other answers to this question). Any of those are a more C++ way than manually handling the pointer to the array, IMHO.

Dynamiter answered 5/2, 2010 at 0:8 Comment(14)
this doesn't really answer the question that was asked.Vail
Should I always use std::vector instead of dynamically allocated arrays? What are the benefits of using an array over a vector, and vice versa?Haworth
I should have mentioned in my question, that the array must persist after the current scope. Do I have to use new std::vector?Haworth
@John Knoller: The OP asked about a C++ way to do it, I'd say that vector is the c++ way to do this. Of course, you are correct that there might be situations that still would call for a plain array and not knowing the OP's situation this might be one. I'd guess no though, since it seems plausible that the OP does not know about vectors.Dynamiter
An array is somewhat faster, you control it fairly tightly. OTOH, you have to manage freeing the memory. When interfacing with C, sometimes you have to pass C functions an array. For most situations, vector is all you need.Cuticle
@dreamlax: If it must persist after the scope, I would still prefer using a vector instead of an array. Only I would wrap it in a shared_ptr to make sure that it gets deleted. Using a shared_array is another option if you really must use a real array. (for a description of shared_ptr/shared_array, see www.boost.org).Dynamiter
@villintehaspam: Although this solution doesn't answer my question it is the path I am going to take. Tyler McHenry answers my question more directly, and should help especially for people who cannot—for whatever reason—use std::vector.Haworth
@villintehaspam: what if you are the guy writing std:vector? what do you do then? someone has to do the job rather than just punting it into a library.Vail
@John Knoeller: as I've pointed out many times before, you do NOT use a dynamically allocated array to implement std::vector. You use ::operator new to allocate memory, and placement new to create objects in that memory -- it's substantially different, and new[] simply won't work (e.g., it immediately creates objects in all the memory allocated, which std::vector can't do).Costanzo
@Jerry: std::vector sure as hell doesn't use stack allocation or const, so it must be dynamic allocation at some level. if the answer dreamlax's question is that new[] automatically inits the array, then it would be nice if someone actually said that instead of deflecting.Vail
@villintehaspam: No, it is not a C++ way to do it. It is Java way to do it. Sticking vector everywhere regardless of context is called "Writing Java code in C++".Pigeontoed
@John Knoeller: I was very specific in saying it doesn't use a dynamically allocated array. I already talked about what it does to allocate storage. The bottom line is that there's almost never any reason to use new[] -- even if you are the one implementing std::vector or something similar.Costanzo
@Jerry: Ok, I'll accept that. I've never had any use for new[], but I thought that was just me.Vail
@AndreyT: I agree that always using vector over a dynamic allocated array isn't a good statement. However I would still argue that using a vector over a dynamically allocated array is the C++ way to do it and it should definitely be the preferred choice unless there is some particular reason to use a dynamically allocated array. This isn't writing Java code, it is getting the job done with minimal effort and lower risk of errors.Dynamiter
N
2

std::fill is one way. Takes two iterators and a value to fill the region with. That, or the for loop, would (I suppose) be the more C++ way.

For setting an array of primitive integer types to 0 specifically, memset is fine, though it may raise eyebrows. Consider also calloc, though it's a bit inconvenient to use from C++ because of the cast.

For my part, I pretty much always use a loop.

(I don't like to second-guess people's intentions, but it is true that std::vector is, all things being equal, preferable to using new[].)

Neopythagoreanism answered 5/2, 2010 at 0:10 Comment(0)
S
2

you can always use memset:

int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
Spatterdash answered 5/2, 2010 at 0:14 Comment(7)
I understand that I can use memset, but I wasn't sure if this was the C++ way to approach the problem.Haworth
Yup, memset works just as well in C++ as in C for setting linear memory to a value.Spatterdash
@gbrandt - while that may be true, I wouldn't say it's "the C++ way". There are more "accepted" ways of doing it.Ailanthus
It's not really the 'the C++ way', but then neither are raw arrays.Gens
@gbrandt:Which is to say that it doesn't work very well in either C or C++. It works for most values of the type is char or unsigned char. It works for most types of the value is 0 (at least in most implementations). Otherwise, it's generally useless.Costanzo
10 * sizeof( *myArray ) is more documented and change-proof than 10 * sizeof( int ).Declamation
In any case, the OP has a raw array and memset is the fastest and easiest way to zero that array.Spatterdash
S
0

For c++ use std::array<int/*type*/, 10/*size*/> instead of c-style array. This is available with c++11 standard, and which is a good practice. See it here for standard and examples. If you want to stick to old c-style arrays for reasons, there two possible ways:

  1. int *a = new int[5](); Here leave the parenthesis empty, otherwise it will give compile error. This will initialize all the elements in the allocated array. Here if you don't use the parenthesis, it will still initialize the integer values with zeros because new will call the constructor, which is in this case int().
  2. int *a = new int[5] {0, 0, 0}; This is allowed in c++11 standard. Here you can initialize array elements with any value you want. Here make sure your initializer list(values in {}) size should not be greater than your array size. Initializer list size less than array size is fine. Remaining values in array will be initialized with 0.
Suannesuarez answered 19/2, 2021 at 7:7 Comment(2)
The size for std::array<> must be known at compile-time. It is not possible to declare std::array<> based on a size determined at runtime, so it is not always practical or possible to use std::array<> over new[] or std::vector<>.Haworth
@Haworth yes totally agree with you. We can use only fixed size array with std::array<> whose size must be known at compile time.Suannesuarez
C
-1

Typically for dynamic lists of items, you use a std::vector.

Generally I use memset or a loop for raw memory dynamic allocation, depending on how variable I anticipate that area of code to be in the future.

Cuticle answered 5/2, 2010 at 0:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.