I read allready about some ways like doing this for known amount of values like:
new int[3] {0 , 0, 0};
After this remembered me of the way of initializing arrays on declaration in C
I asked my self about it is also valid in C++ to do this:
new int[n] {}
Where the empty Braces cause everything to be 0-initialized.
After trying out it looks fine to me, but could also just be caused by randomness and in real UB or something.
And if it is valid, are there also ways to init on a specific value?
note:
I want to achieve the same as a call to calloc (n, sizeof(int)); would do. But since I'm now in C++ and not C anymore I won't use theese functions anymore to keep the code readable.
note2:
When saying
I want to achieve [...]
It is corresponding to my minimal example, at all I just want to obtain a zero initialized block of valid memory.
auto array = new int[n] ();
This performs zero initialisation, since int is a "non class type".
auto array = new int[n];
This doesn't. The initial values are indeterminate. Note though that the background behind this is very confusing and the description in the standard changed a few times, probably to make it less confusing, which IMHO failed to achieve its effect. Some relevant links therefore:
http://en.cppreference.com/w/cpp/language/zero_initialization
What do the following phrases mean in C++: zero-, default- and value-initialization?
Meaning of default initialization changed in C++11?
(Do also read the comments)
[...] I simply need an zero intialized memory block, not any vector or array implementation...
std::vector is a simple memory block. Use it. The additional member functions that are provided by it have no cost unless you use them. There won't be any resizing if you don't need it. Use it for the same reasons that you should prefer std::unique_ptr or std::shared_ptr over a raw pointer whenever possible!
I would not use new operator and use C++ STL containers such as std::vector or std::array. Here a small example since you know the size at compile time :
std::array<int,3> foo{}; // will initialize a std::array with 0 value.
For some more explanations about the initialization :
new int[5] () is zero initialization it is valid and initialize elements to 0.
2) As part of value-initialization sequence for non-class types and for
members of value-initialized class types that have no constructors.
new int[5] is default initialization you are not guaranteed about it, since the values are filled arbitrary.
If T is an array type, every element of the array is default-initialized.
Simply writing new int[n] just allocates memory and initializes nothing, so given bytes still have values from another usage in past which is unknown.
With adding brackets, C++ adds a construction and fills empty fields with zero.
For more, read this.
You can use std::vector.
std::vector<int> x(5);
The main advantage here is that std::vector is actually safe, unlike new.
Related
The dynamically created array of objects need to use a non-default constructor, and the problem I'm running into I think is the syntax. In my mind, the fact that I'm able to do this
int * somePtr = new int[5];
means that I should be able to do this
IntegerSet* someSet = new IntegerSet(this->getLength())[5];
where IntegerSet is a class I have made that represents an integer set. this code is happening inside one of IntegerSets member function. When I try this I get a syntax error
"cannot convert from IntegerSet to IntegerSet*"
I understand what this means, the two types aren't equivalent, but I can't see the difference between doing what I did in part 1 and part 2, besides the fact that part 2 has to have an argument list passed as the constructor. So it is in that part of the code that I suspect I have the syntax wrong
new expression allows only default initialization, you can not do this within single new expression. What you could do is allocate raw memory and construct objects one by one using placement new (see this answer in Object array initialization without default constructor)
Or yet even better, don't use C-style arrays. Instead, use some STL container such as std::vector and it's constructor, where the 2nd argument is a value that will be used to initialize elements:
std::vector<IntegerSet> integers(5, IntegerSet(this->getLength()) );
There is an easy way out of this problem: add a default constructor to IntegerSet that does not acquire memory and any other resources. This way you can allocate an array of IntegerSet with new and then fill each element of the array on the next step.
Even better solution: use std::vector<IntegerSet> and emplace_back() to initialize each element of the array using a non-default constructor.
In my C++ project, there is a class which needs to create an array of objects.
Between different instances of the class, the size of the array will be different, which is why I chose to use an array.
If I do :
int numberOfPlayers; // This is determined at run time.
int *players;
//In constructor
players= new int[numberOfPlayers]; // This works
But if I do:
Character *players;
players = new Character[numberOfPlayers]; // Compiler complains
The Compiler complains "No matching constructor for initialisation of Character"
How do I dynamically declare an array of type "Character".
Note: Character has nothing to do with char. Character is a name of an class I created myself.
EDIT: Character does not have a default constructor, since it needs to be passed several arguments so it can be initialised with the proper state. The only constructor is has takes several arguments.
EDIT: I chose a dynamically created array, over a vector since I know during the lifetime of the instance, the size of the array will be constant, though between different instances the size will be different. I thought this would make sense for performance reasons (memory / speed).
The "proper" way is to use std::vector. It is a fast, safe, more robust alternative to horrible new.
std::vector<Character> vec;
vec.push_back(Character(params));
vec.push_back(Character(other_params));
If you know the size ahead, you can avoid reallocation overhead by using std::vector::reserve
std::vector<Character> vec;
vec.reserve(50);
vec.push_back(Character(params));
vec.push_back(Character(other_params));
The overhead of std::vector is practically non-existent.
Now, the reason why you can't do this your way, it's because by default new uses default constructor, and it doesn't exist.
The problem is that your type Character does not define a default constructor of the form:
Character::Character()
{
// etc.
}
Your type needs a default constructor. Unlike C's malloc, operator new constructs instances for you at the time of allocation. It then follows that it requires a parameterless (default) constructor as it provides no way to pass arguments. So...
class Character
{
public:
Character(){}
};
"Character does not have a default constructor, since it needs to be passed several arguments so it can be initialised with the proper state. The only constructor is has takes several arguments"
Then an array is the wrong type to use, because an array will always default-construct its members.
Use:
std::vector<Character> players;
The size can vary, as you wanted, and you can call players.push_back( character ) when each character has been constructed
The short answer is that you can't do this because the standard doesn't allow it. There's no technical reason it couldn't be allowed--it just isn't.
Some compilers (e.g., gcc) have supported it as an extension to C++ for years. It's also been supported in C by various compilers for long enough that C99 standardized it, so all (reasonably current) C compilers now support it.
There was a proposal to add an array-like class with a size determined when it was created, and remaining constant after that, but the committee decided against accepting it1. That leaves only std::array, which requires a size determined at compile time, and std::vector, with a size that can vary dynamically at run time.
In fairness, however, if you do know the size of a vector when you create it, you can specify the size at creation time. While it's certainly still capable of resizing itself, that functionality is mostly in resize and push_back. If you simply don't use those, the overhead from using std::vector compared to a native array is generally quite minimal anyway, so you're unlikely to see significant gains from other techniques (except, perhaps, under rather obscure circumstances).
1. At least IMO, this was the right decision--although I can see the basic reasoning behind the idea, I think the proposal was sufficiently flawed that we're better off without it.
Because allocating an array of Character means that the array will contain an amount of Character instances. When you allocate the array, each instance contained must be initialized somehow and the default constructor is required.
You have to declare Character::Character() { } to let the compiler invoke it. If you can't provide a default constructor then you should consider using a Character** so that you can init them as you wish, eg:
Character **array = new Character*[amount];
array[0] = new Character(...);
Mind that this requires to delete each instance, so instead of having delete[] array you will need
for (int i = 0; i < amount; ++i)
delete array[i];
delete [] array;
An additional way would be to forget about arrays and use a std::vector:
vector<Character> character;
character.push_back(Character(...));
Which would also relief the need to manage memory by yourself.
The dynamically created array of objects need to use a non-default constructor, and the problem I'm running into I think is the syntax. In my mind, the fact that I'm able to do this
int * somePtr = new int[5];
means that I should be able to do this
IntegerSet* someSet = new IntegerSet(this->getLength())[5];
where IntegerSet is a class I have made that represents an integer set. this code is happening inside one of IntegerSets member function. When I try this I get a syntax error
"cannot convert from IntegerSet to IntegerSet*"
I understand what this means, the two types aren't equivalent, but I can't see the difference between doing what I did in part 1 and part 2, besides the fact that part 2 has to have an argument list passed as the constructor. So it is in that part of the code that I suspect I have the syntax wrong
new expression allows only default initialization, you can not do this within single new expression. What you could do is allocate raw memory and construct objects one by one using placement new (see this answer in Object array initialization without default constructor)
Or yet even better, don't use C-style arrays. Instead, use some STL container such as std::vector and it's constructor, where the 2nd argument is a value that will be used to initialize elements:
std::vector<IntegerSet> integers(5, IntegerSet(this->getLength()) );
There is an easy way out of this problem: add a default constructor to IntegerSet that does not acquire memory and any other resources. This way you can allocate an array of IntegerSet with new and then fill each element of the array on the next step.
Even better solution: use std::vector<IntegerSet> and emplace_back() to initialize each element of the array using a non-default constructor.
Is the name of a vector simply a pointer, just like a vanilla C array?
Thus, I could send the address to a single piece of non-vector data (a pointer, in other words) to a function argument that expects a vector since a vector is also a pointer.
For example, a function that is declared as this:
void RenderingEngine::Render(const vector<Visual>& visuals) const{
Could be called like this:
Visual visual; // is NOT a vector
//do stuff with visual
m_renderingEngine->Render(&visual);
Makes sense and is valid, legal C++?
This example code is from an O'Reilly C++ book, so I guess it is an error in the book.
Is the name of a vector simply a pointer, just like a vanilla C array?
No. It's a fully-formed class.*
* What's more, a vanilla C array is not a pointer either (it just get turns into one in most situations).
No. That doesn't make sense. There is no implicit conversion from T* to std::vector<T>.
But in C++11, you can do something which is very close1 to what you're doing. You could create the vector on the fly while passing the argument as:
m_renderingEngine->Render( {visual} ); //note the curly braces!
With that you create a vector object out of the expression {visual} which then gets passed to the function.
1. very close in the sense that you just have to type one more character to make your code work. Instead of typying &, just type {, and one more } at the end. That is it. Life is so easy with C++11.
No, it isn't, which is rather fortunate because the behaviour of C arrays is abominable. If you find yourself looking for it, I would suggest instead looking for some new learning material w.r.t. C++.
The other answers are correct, but I'd like to add that it works the other way around:
void RenderingEngine::Render(Visual *visuals, size_t n_visuals);
Can be called like this:
vector<Visual> visuals;
m_renderingEngine->Render(&visuals[0], visuals.size());
You just take the address of the first element and pass it as if it was an array. This works because the elements of a vector are laid out sequentially in memory. (As pointed out in the comments, shouldn't use this in new code, of course. It's safer and easier to define you method to take a vector. However, if you already have a legacy function that takes a pointer, this allows you to use vectors in your own code.)
The reason it works this way around, but not the way in your question (pass a pointer, to a function that takes a vector), is that in your case it can't determine the size of the array at runtime. But it has to know the size to construct the vector:
// (wrong code)
// Passing one element:
Visual visual;
m_renderingEngine->Render(&visual);
// Passing two elements, how does Render know that
// there are two elements at that address?
Visual[2] visuals;
m_renderingEngine->Render(&visuals[0]);
As Nawaz pointed out, you can do something similar in C++11:
Visual visual;
m_renderingEngine->Render( {visual} ); // C++11
You can also put more elements in the {}. This only works because the compiler can tell at compile-time how many elements there will be. It's just syntactic sugar for:
vector<Visual> myVec = {visual}; // C++11
m_renderingEngine->Render(myVec);
which in turn works like the classic:
vector<Visual> myVec;
myVec.push_back(visual);
m_renderingEngine->Render(myVec);
(although the C++11 version might be slightly optimized, I don't know for sure).
boost::array (or the tr1or std version) offer some nice additional features over a built-in array.
Up to now, our codebase only contains built-in arrays, for example (made up, but the style matches):
WORD m_lastReadFlags[FLAGS_MAX];
...
WORD flagBuffer[FLAGS_MAX];
if (getFlags(flagBuffer)) {
memcpy(m_lastReadFlags, flagBuffer, sizeof(m_lastReadFlags));
...
I think one'll get the idea.
Now, my question is, for those places in the code, where dropping in boost::array would make sense (because of other changes made), is array a 100% semantics preserving drop-in for the built in array? (Possible compiler errors are OK -- only silent behavioral changes are what's bothering me.)
That is, could above code be re-written (for example) to use:
boost::array<WORD, FLAGS_MAX> m_lastReadFlags;
and the memcpy (possibly adapted to use c_array()or data()) and other array-like access would remain the same? Yes, of course I could also replace the local buffer by an array and remove the memcpy or use std::copy or something like that, but the point of this question is about the compatibility of built-in arrays and the array class.
Update: One thing that's bothering me specifically is the places (like in the memcpy case) where the built-in arrays are used as pointers. Will all occurences be caught by the
compiler / handled correctly?
What about assignment?
T arr1[N]; // or array<T, N>
T arr2[N]; // or array<T, N>
T* p1;
...
// Note, not all combinations will compile:
arr1 = arr2;
p1 = arr1;
arr2 = p1;
...
Yes, that should be fine, since the array class is precisely a wrapper for an automatic array. It has the same access syntax with square brackets, and if you need to get at the pointer, you know how to do it. You can even use std::copy everywhere and use iterators; chances are that that will be implemented by memcpy anyway.
The array class is of aggregate type (no non-trivial constructors/destructor/assignment), so you can initialize it with the traditional aggregate (brace) initializer, just like a plain array.