How can you have an "unlimited" number of classes (eg. they are allocated as they are needed) rather than allocating like 100 instances when your program starts? I know there are "Linked Lists" but I am wondering if there are any easier ways for making a bunch of instances.
This question is kinda hard to explain, but basically I want to know what the best way is to have classes created as they are needed rather than allocating unnecessary instances (eg. allocating 100 and the user only needs 3). Vectors? Linked lists? Any other ways? Please be specific because I am very new to C++.
If by "unlimited" you mean "arbitrary", and by "classes" you mean "objects", then that's always possible.
Vectors and linked lists both work for what you want to do, but they are used for different growth and access patterns.
When to use vectors: When the number of objects increase either few times, or by big increments. More importantly, when the objects need to be quickly accessed randomly (e.g. first index 4, then 145641, then 122).
When to use linked lists: When it's necessary to insert objects in the middle of the list (e.g. to add sorted). When it's okay to only be able to sequentially access nodes (e.g. 1, 2, 3; or 7, 6, 5).
It's also possible to do it without using vectors or lists, by means of arrays of pointers and dynamic allocation.
For a newbie, vectors are probably the easiest to use.
The best way to do this is using dynamic allocations. Assume you have the following class:
1 2 3 4 5 6 7 8 9 10 11
class employee
{
private:
string name;
string ID;
public:
employee(string, string); //Constructor
~employee(); //Destructor
//Get and Set methods
};
when you want to create an instance of this class, for example adding an employee to the system you would do the following:
employee* newEmp = new employee("Bob", "234980");
What this does is create a new employee object (this calls the constructor and provides the name "Bob" and ID "234980")
It then sets the pointer newEmp to the new employee so you now have a way to access it.
In doing this you can create a new employee object only when needed. Also, you should always remove dynamic storage when you're done with it. You can do this using 'delete' like so:
delete newEmp;
Now if you're talking about storing multiply employees you can always create a linked list or vector with each node containing an employee object.
I know I need to use dynamic allocation but how can I make multiple instances and keep track of all of them. For example
employee[0].foo();
employee[1].foo();
I need to make multiple objects while keeping an index for all of them.
The only way I can think of doing this is by making an array:
employee earray[100];
However creating 100 objects is a waste of memory when only 5 may be needed. I think once I get the concept of multiple objects, I will be good at c++.
That's static allocation.
Dynamic allocation would be like this:
1 2 3 4
employee *earray[100000]={0}; /*The actual size of this is sizeof(void *)*100000. For x86, ~390K. {0} sets all elements to zero, which is an easily identifiable invalid pointer.*/
int actually_needed_objects=/*...*/;
for (int a=0;a<actually_needed_objects;a++)
earray[a]=new employee(/*parameters for the constructor*/);
When you're done with an object, you have to delete it and mark the subindex as free by setting it to zero:
1 2
delete earray[i];
earray[i]=0;
With vectors:
1 2 3 4
std::vector<employee> earray;
earray.reserve(100000); /*Optional. Reduces time needed for push_back()s until the size hits 100k.*/
int actually_needed_objects=/*...*/;
earray.resize(actually_needed_objects); /*For this to work, employee needs a constructor with no parameters.*/
You can remove elements like this:
earray.erase(i);
The vector automatically packs everything so there are no empty elements.
For what you are trying to do, I recommend a std::deque over other options.
As helios already noted, std::vectors are good for large granularity and have the best access time -- because they are stored in continuous memory (just like statically allocated arrays).
A std::deque is very much like a vector, but the data need not be in one continuous block of memory, so access time is affected. It is useful if you have a very large amount of data (meaning it can store more than a vector on most systems).
A std::list is a linked-list, and has the poorest access time, but also the best insertion/deletion characteristics.
employee *earray[100000]={0}; /*The actual size of this is sizeof(void *)*100000. For x86, ~390K. {0} sets all elements to zero, which is an easily identifiable invalid pointer.*/
int actually_needed_objects=/*...*/;
for (int a=0;a<actually_needed_objects;a++)
earray[a]=new employee(/*parameters for the constructor*/);
I understand the whole dynamic concept but the problem is I don't know what actually_needed_objects should be because the objects need to be created as the user needs them.
Second Question:
If I use a vector, do I use a vector of pointers or a vector of objects?
I don't know what actually_needed_objects should be because the objects need to be created as the user needs them.
Standard library containers can increase their size
If I use a vector, do I use a vector of pointers or a vector of objects?
That depends on what you are using the vector for: if you want to use polymorphic derived classes, you should use vectors of pointers; if you want to have automated memory management, you should use vectors of objects
I think the simplest and easiest way for you to go about this is by using the STL list or STL deque (depending on how you want to be able to access the data)
The easiest thing to do is to create the object you need to create and push it into the list or deque. The STL already has all the functions you need built in. This will automatically increase the size of the list or deque without overflow or errors. You never need to predefine the size which is part of what sets them apart from arrays. (This means your 'actually_needed_objects' isn't necessary)
Now when you want to access them you can use iterators to loop through the data structure and find it by value.
Again the STL has all the functions built in for deleting, retrieving, pushing, etc so most of the work is done
It's usually best to use a vector of pointers. It can significantly reduce the resizing time. You do have to manage memory yourself, but that's a small drawback, IMO.