Array of objects with constructor - c++

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.

Related

How do I dynamically allocate an array of objects in C++ with individual constructor parametes for each object?

Let's assume that I have a class
class Foo
{
public:
Foo (const std::string&);
virtual ~Foo()=default;
private:
//some private properties
};
And I want to create many instances of this class. Since I aim for good performance, I want to allocate the memory at once for all of them (at this point, I know the exact number but only at runtime). However, each object shall be constructed with an individual constructor parameter from a vector of parameters
std::vector<std::string> parameters;
Question: How can this be achieved?
My first try was to start with a std::vector<Foo> and then reserve(parameters.size()) and use emplace_back(...) in a loop. However I cannot use this approach because I use pointers to the individual objects and want to be sure that they are not moved to a different location in memory by the internal methods of std::vector. To avoid this I tried to delete the copy constructor of Foo to be sure at compile time that no methods can be called that might copy the objects to a different location but then I cannot use emplace_back(...) anymore. The reason is that in this method, the vector might want to grow and copy all the elements to the new location, it does not know that I reserved enough space.
I see three possibilities:
Use vector with reserve + emplace_back. You have the guarantee that your elements don't get moved as long as you don't exceed the capacity.
Use malloc + placement new. This allows you to allocate raw memory and then construct each element one by one e.g. in a loop.
If you already have a range of parameters from which to construct you objects as in the example, you can brobably (depending on your implementation of std::vector) use std::vector's iterator based constructor like this:
std::vector<Foo> v(parameters.begin(),parameters.end());
First solution has the advantage to be much simpler and has all the other goodies of a vector like taking care of destruction, keeping the size around etc.
The second solution might be faster, because you don't need to do the housekeeping stuff of vector emplace_back and it works even with a deleted move / copy constructor if that is important to you, but it leaves you with dozens of possibilities for errors
The third solution - if applicable - is imho the best. It also works with deleted copy / move constructors, should not have any performance overhead and it gives you all the advantages of using a standard container.
It does however rely on the constructor first determining the size of the range (e.g. via std::distance) and I'm not sure if this is guaranteed for any kind of iterators (in practice, all implementations do this at least for random access iterators). Also in some cases, providing appropriate iterators requires writing some boilerplate code.

How do I copy arrays that contain non primitive types?

I'm writing C++ on an Arduino. I've run into a problem trying to copy and array using memcpy.
Character characters[5] = {
Character("Bob", 40, 20),
Character("Joe", 30, 10),
...
};
I then pass this array into a constructor like so:
Scene scene = Scene(characters, sizeof(characters)/sizeof(Character));
Inside this constructor I attempt to copy the characters using memcpy:
memcpy(this->characters, characters, characters_sz);
This seems to lock up my application. Upon research it appears that memcpy is not the right tool for this job. If I comment that line out the rest of the application continues to freeze.
I can't use vectors because they're not supported on the Arduino, neither is std::copy. Debugging is a pain.
Is there any way to do this?
Edit
The reason why I am copying is because multiple objects will get their own copy of the characters. Each class can modify and destroy them accordingly because their copies. I don't want to have the Scene class responsible for creating the characters, so I'd rather pass them in.
You will have to copy the members individually, or create a copy constructor in the Character class / struct
It's very unclear what's going on in your code.
First of all, you aren't using std::array as your question title suggests, you are using a built-in array.
You could concievably use std::array instead, and just use copy constructor of std::array. But that brings us to second question.
When you are doing memcpy in the constructor of Scene, what is the actual size of this->characters? It's not a good thing to have a constructor that takes characters_sz dynamically if in fact there is a static limit on how many it can accept.
If I were you and really trying to avoid dynamic allocations and std::vector, I would use std::array for both things, the member of Scene and the temporary variable you are passing, and I would make the constructor a template, so that it can accept arbitrary sized std::array of characters. But, I would put a static assert so that if the size of the passed array is too large, it fails at compile time.
Also assuming you are in C++11 here.
I guess depending on your application, this strategy wouldn't be appropriate. It might be that the size of the arrays really needs to be variable at run-time, but you still don't want to make dynamic allocations. In that case you could have a look at boost::static_vector.
http://www.boost.org/doc/libs/1_62_0/doc/html/container/non_standard_containers.html
boost::static_vector will basically be like a heap-allocated buffer large enough to hold N objects, but it won't default construct N of them for sure, you may have only one or two etc. It will keep track of how many of them are actually alive, and basically act like a stack-allocated std::vector with a capacity limit of N.
Use std::copy_n:
std::copy_n(characters, num_characters, this->characters);
Note that the order of arguments is different from memcpy and the number is the number of elements, not the size of those elements. You'll also need #include <algorithm> in the top of your source file.
That said, you're probably better off using a std::vector rather than a fixed size array, That way you can just use a simple assignment to copy it, and you can grow and shrink it dynamically.

Why can't one dynamically declare an array of objects in C++ like this :

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.

std vector construct element once [duplicate]

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?

Why is this allocation of a vector not accepted?

So I have declared a vector in my class header like this:
...
private:
vector<Instruction> instructions;
...
Then in the .cpp implementation in the constructor, I try to initialize it like this:
instructions = new vector<Instruction>();
Xcode tells me: No viable overloaded '='
I am basically trying to get this class to behave like I would expect in java, where instances of the class retain this vector. Thats why I wanted to dynamically allocate it using new, so as to make sure that it doesn't get lost on the stack or something. Any help would be appreciated with this, thanks so much.
In order to do what you're trying to do the instructions = new vector<Instruction>() line is entirely unnecessary. Simply remove it. The vector will automatically get default-constructed when an instance of your class gets constructed.
An alternative is to make instructions into a pointer, but there doesn't appear to be any reason to do this here.
when you write
vector<Instruction> instructions;
you already have instantiated instructions to whatever memory model the user of your class is using e.g.
class YourClass
{
vector<Instruction> instructions;
};
...
int main()
{
YourClass class1; // stack
std::unique_ptr<YourClass> class2(new YourClass); // heap
...
}
In your class, you declare a std::vector<Instruction>. new vector<Instruction>(); returns you a std::vector<Instruction>*.
operator new returns a pointer, so you have a type mismatch.
The real issue is the fact that you are doing it at all. Do you have a good reason for dynamically allocating that vector? I doubt it, just omit that entirely as it will be allocated along with instances of your type.
You have a member value but you try to initialize it from a vector<Instruction>*. Initialize it from vector<Instruction> or change the declaration to a pointer. If you go down the second route, you need to observe the rule of three.
You might also want to get a decent C++ book from this list.
Also, I think you have a using namespace std; in your header which is bad.
Do not use new in C++ unless you know what you are doing. (Which you do not, currently.)
Instead use automatic objects. You already defined instructions to be an automatic object. You just need to init it as if it were one:
class wrgxl {
public:
wrgxl()
: instructions() // this initializes the vector using its default constructor
{
// nothing needed here
}
...
private:
vector<Instruction> instructions;
...
};
The initialization of instructions in the constructor's initialization list is optional, though, if you only want to call the default constructor anyway. So in this case, this would be enough:
wrgxl()
{
}
If you wanted to dynamically allocate a vector, you would need to make instructions a pointer to a vector. But this rarely ever make sense, since the vector already allocates its data dynamically, but wraps this, so you do not have to deal with the ugly details resulting from this.
One of those details is that, if you have a dynamically allocated object in a class, you will then have to worry about destruction, copy construction, and copy assignment for that class.
As Kerrek already pointed out, you will need to have a good C++ book in order to properly learn C++. Make your pick.
I think you are confusing C++'s with C#'s syntax.
First, unlike in many languages, variables allocated on the stack (such as yours), are initialized by calling the default constructor, so I suspect that what you are doing is unnecessary.
Second, in order to do what you are trying to do, you use the following syntax:
instructions = vector<Instruction>();
however, as I said, this is likely redundant (and wasteful on a non-optimizing compiler as it might call both the constructor and the assignment operator). A much better way to do this is found in sbi's answer.
Third, unlike in C#, the new operator allocates memory on the heap and returns a pointer to the newly allocated data. Your variable instructions is not a pointer, thus the error.