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 u开发者_运维技巧se memset
? Is there a “C++” way to do it?
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.
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
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).
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++)
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.
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:
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
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.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()
.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
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[]
.)
you can always use memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
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:
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 caseint()
.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.
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.
精彩评论