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.
Related
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.
I'm currently trying to program an array of objects in a c++ program. However it keeps giving me errors when trying to create the arrays.
So on top of my code I have the following code:
#define sensNumber 4
ros::Publisher pub_range2 [sensNumber];
this gives the error:
multisone2.ino:19:38: error: no matching function for call to ‘ros::Publisher::Publisher()’
So it's trying to call the constructor for Publisher, why? And how do I stop it?
Now I know this can also be done with Vectors but I'm trying to optimize the code esp. for reading speed so I would rather avoid vectors(yes I know that it remains linair but accessing this array represents a significant portion of my code).
As you're trying to stack-allocate sensNumber instances of ros::Publisher, the default constructor must be called.
An alternative would be to allocate an array of pointers to ros::Publisher. Better still, an array of std::unique_ptr or std::shared_ptr.
When you declare an array of c++ objects you're actually instantiating each element. This means that the default parameterless constructor is called for each array element. If you don't want to instantiate all elements when declaring your array, you should declare an array of pointers instead and then initialize each element whenever required.
I have class named Novel. I can declare array of objects as mentioned below:
Novel obj;
but problem is Novel has constructor which I want to be called for all indexes of array how can I do that. I tried following but it does not work.
Novel obj(i,n)[2];
You need to use a proper container that uses dynamic allocation to defer construction of individual elements.
std::vector<Novel> objs(2, Novel(i,n));
http://en.cppreference.com/w/cpp/container/vector/vector
Unfortunately the C++ language does not provide that capability. Arrays are allocated, but by default they are not initialised at all. If they are allocated in static storage they get filled with zeros; you can give a brace-initialiser; and you can provide a default constructor to initialise each value. What you cannot do is initialise an array with any other constructor.
To achieve a similar effect you have to approach the problem from a different angle. Basically, you can:
- write a macro or template that both allocates an array and calls a constructor on each element under the covers, or
- create an object with array semantics, which can initialise itself any way you like.
The built in collection classes are usually the best solution. For example, std::vector provides fill, range and copy constructors as well as array semantics. One of the other answers provides an example, but there are several ways to do it.
std::vector<Novel> objs(2, Novel(i,n));
It's not an array, but it should do what you need.
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.
This question already has answers here:
How can I create objects while adding them into a vector?
(5 answers)
Closed 9 years ago.
This is a pretty straight forward question.
Is there a way to have a vector and initialize an element without constructing and then copying it?
class BigType
{
// has a costly copy constructor
};
int main(void)
{
using std::vector;
vector<BigType> bigTypeVec;
bigTypeVec.push_back(BigType(/*constructor from parameters*/));
// This constructs a temp object, and then copies it to the new element.
}
Of course there are all sorts of work-a-rounds involving vectors of pointers, or instead of using a constructor, initialize an element's components with set functions, however I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back.
Edit: This question was marked as a duplicate, however I had viewed that page and the answers to his question hadn't answered mine. I want to know how to set the value of the element by constructing it once, rather then copy constructing a temporary object into the element. Emplace was a good way to do this.
You could use std::vector<...>::emplace() or, if you want to append the object, std::vector<...>::emplace_back(), to construct the object in place. If you have to use C++03 this member function isn't available. As an approximation you could push_back() and empty object and then swap() your BigType into the corresponding location, assuming you could construct a small empty object.
Note that std::vector<...> isn't necessarily the best data structure if you have huge objects: if the reserved spaces runs out, the vector need to shuffle the objects around to make new space. You might want to use std::deque<...> instead, as it won't leave its objects put (unless you insert into the middle) while having similar access characteristics as std::vector<...>.
with C++11, yes.
bigTypeVec.emplace_back(BigType());
Here's some more info:
http://en.cppreference.com/w/cpp/container/vector/emplace_back
"Is there a way to have a vector and initialize an element without constructing and then copying it?"
Yes.
Consider placement new as a mechanism to side-step the use of a copy assignment and it's use of a temporary.
"Is there a way to have a vector..."
A vector can be built with elements created with the default constructor.
I believe it is possible to define BigType so that no element initialization is required during the bigTypeVec construction. In this way, declaring the vector (or even a simple array) will trigger no element constructor work. Consider these:
vector<BigType> bigTypeVec;
or
BigType bigTypeVec[MAX_BigTypeVecSize];
Note that the array requires BigType to provide a default constructor (or you to provide a big bunch of curly brace array initialzation).
However, I can imagine that you might find value for each BigType element to have an indication that it is or is not initialized.
" and initialize an element without constructing [a temp] and then copying it [, the temp, to the vector]?"
Placement new can then be used to construct the object in place. By passing the address of the desired bigTypeVec element you wish to initialize to the placement new, all the element constructor work will occur where (in memory) you want it. Consider something like:
vector<BigType> bigTypeVec;
BigType* pBT = 0;
pBT = new (&bigTypeVec[0] BigType(<param>); // placement new
pBT = new (&bigTypeVec[1] BigType(<param>);
...
pBT = new (&bigTypeVec[n] BigType(<param>);
Note the discard of pBT. Pointer is not used.
*"I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back."*
At this point, all that remains is to create the simplest class possible that inherits from std::vector() and re-impliments "push back", or perhaps a new method that supports your needs. These methods would seek the vector element that push-back would have found, and use the placement new similar to above.
Are you sure about this?
"This constructs a temp object, and then copies it to the new element."
As far as I know, it will directly create an object at the memory location. Return value optimization. Temporary will not be created.
Am I wrong?