I was under the impression that I needed to use "new" in order to create a "permanent" object. |
If you use
new to create an object, then you do have control over the lifetime of that object, true. If you simply create local object on the stack, then it will be destroyed when it falls out of scope.
In the code you posted, however, this is an irrelevance. You're creating your BarHost object in the main function, so it will remain in scope until the program exits. You don't need to worry about dynamically allocating it in this case.
As a general rule, you shouldn't dynamically allocate stuff unless you
need to, because you want to minimize the amount of memory management you have to do in your code.
Under other, more complicated circumstances, you might very well need to dynamically allocate, but not in the code you've shown us.
If I don't use new, then if for example I create several BarHost objects inside a for loop, storing them say in a vector, won't they simply overwrite each other? |
If you're storing the actual objects in the vector, like so:
1 2 3 4 5 6
|
std::vector<BarHost> myVector;
for (int i = 0; i < NUM_OBJECTS; ++i)
{
BarHost newObj;
myVector.push_back(newObj);
}
| |
then there's no problem, because when you store something in a vector, you actually store a
copy of it. The vector owns that copy and manages the memory for it, so it's safe regardless of what you do in your code.
In detail, what happens is the following:
1) You enter the first iteration of the loop.
2) You create a BarHost object on the stack.
3) When you add that BarHost object to the vector, the vector creates its own copy of it, with its own memory allocated for that copy.
4) You exit the first iteration of the loop.
newObj drops out of scope, and the memory for it is no longer reserved, but it doesn't matter, because myVector has already stored its own copy.
5) You enter the 2nd iteration of the loop.
6) You create another BarHost object on the stack. This may re-use the same memory as the first one, or may use different memory - that's up to the operating system to decide. Either way, it won't damage myVector, because it's storing its own copy in other memory.
7) This second BarHost object gets copied into the vector, with the vector storing this copy alongside the first.
8) And so on...
EDIT:
Now, if you were just storing pointers to BarHost objects in the vector, things would be different:
1 2 3 4 5 6 7
|
std::vector<BarHost*> myVector;
for (int i = 0; i < NUM_OBJECTS; ++i)
{
BarHost newObj;
myVector.push_back(&newObj);
// TROUBLE - the memory that the pointer in the vector points to is about to be trashed.
}
| |
The only thing you're copying into the vector now is the
address of
newObj. Now, when you reach the end of a loop iteration, newObj drops out of scope, which means that the memory that was storing it is no longer reserved, and can be overwritten with other things. But your vector is still storing an address to that memory, despite the fact that it no longer contains what it did.
You see the problem?
In this case, you'd need to dynamically allocate:
1 2 3 4 5 6 7 8
|
std::vector<BarHost*> myVector;
for (int i = 0; i < NUM_OBJECTS; ++i)
{
BarHost* pNewObj = new BarHost();
myVector.push_back(pNewObj);
}
// BUT WHAT FREES UP THE MEMORY YOU'VE ALLOCATED?
| |
This is fine, but because you've dynamically allocated that memory, you (or rather, the code you write, is going to have to take responsibility for freeing it. Where should this be done? When should this be done? Which classes and/or functions are responsible for doing it? How can you be sure it's not going to be freed twice? How can you be sure that nothing's going to try and use that pointer after the memory's been freed?
These are not always easy questions to answer. There are ways to design your code to make dynamic allocation safer and easier, but that's beyond the scope of this post.