I'm a bit confused about handling an array of objects in C++, as I can't seem to find information about how they are passed around (reference or value) and how they are stored in an array.
I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?
In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space. I try to create a dynamic array of myClass objects within a myContainer. In the myContainer.addObject() method I attempt to make a bigger array, copy all the objects into it along with a new object, then delete the old one. I'm not at all confident that I'm cleaning up my memory properly with my destructors - what improvements could I make in this area?
class myClass
{
private:
string myName;
unsigned short myAmount;
public:
myClass(string name, unsigned short amount)
{
myName = name;
myAmount = amount;
}
//Do I need a destructor here? I don't think so because I don't do any
// dynamic memory allocation within this class
};
class myContainer
{
int numObjects;
myClass * myObjects;
public:
myContainer()
{
numObjects = 0;
}
~myContainer()
{
//Is this sufficient?
//Or do I need to iterate through myObjects and delete each
// individually?
delete [] myObjects;
}
void addObject(string name, unsigned short amount)
{
myClass newObject = new myClass(name, amount);
myClass * tempObjects;
tempObjects = new myClass[numObjects+1];
for (int i=0; i<numObjects; i++)
tempObjects[i] = myObjects[i]);
tempObjects[numObjects] = newObject;
numObjects++;
delete newObject;
//Will this delete all my objects? I think it won't.
//I'm just trying to delete the old array, and have the new array hold
// all the objects plus the new object.
delete [] myObjects;
myObjects = tempObjects;
}
};
An array in C++ is an array of objects laid out in memory.
So for example in:
struct pair {
int x; int y;
};
...
pair array[10];
Each item in the array is going to be with a size of two ints.
If you want an array of pointers you can simply declare one:
pair* array_of_pointers[10];
The string objects have pointers to the variable size part of the string. So they're safe.
In fact they're the important lesson here. Same way you use the string class to avoid excessive memory handling you can use the vector class to avoid all the troubles of handling a dynamic array.
For the case you're doing this as an exercise. Here are a few problems:
newObject needs to be allocated locally, without new. This will make the code correct (as newObject is not a pointer and new returns a pointer) and will also save you the trouble of explicitly handling memory. (On a more advanced note, this makes the code exception safe in one more location)
myObject is never initialized. And you don't use initialization lists in the constructor. The constructor should look like this:
myContainer() : numObjects(0), myObjects(NULL)
{
}
The destructors in the code are exactly as they should be.
No, a dynamic array is not an array of pointers to that type - its a pointer to the first element. The elements are laid out consecutively in memory and are destroyed when the array is delete[]ed.
Thus your deallocation looks fine - you create dynamic arrays of myClass objects so you don't have to delete them individually. You would only have to do this if you had an array of pointers to (dynamically allocated) objects.
There are two definitive errors though:
tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance?
This should be e.g.:
tempObjects[numObjects] = myClass(name, amount);
Also, myObjects is never initialized, which means it contains garbage and dereferencing/using it leads to undefined behaviour.
Finally, unless you are doing this for learning purposes, simply use containers like std::vector that do all the work for you already.
I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?
The array will consist of the objects themselves. If you want to have an array of pointer you will have to declare that:
myClass ** tempObjects;
tempObjects = new myClass*[numObjects+1];
I assume you are used to C# or Java? In those languages objects can only be allocated on heap and are always accessed by referenced. It is possible in C++, but in C++ you can also put objects directly on the stack, or directly construct an array of the objects themselves.
In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space?
Number two: The string object itself is constant in size, but has a pointer to a dynamically sized buffer allocated from the heap.
I think the deallocation looks fine. The code could be written more efficient in various ways, but it looks correct.
Try to test it, to see what happens (yes, that may be compiler-specific, but still)...
You could try to add a custom destructor to myClass (even though you don't need one), that increments a "global" counter when called, Then print the counter after deleting the array.
I would expect the destructor of each object to be called. Note that quite often objects are stored "by-pointers" to allow for inherited objects to be put into the array (avoiding "slicing").
Related
So assuming I have these private data members of a class in a .h file
private:
eventlist *pointer;
int counter;
int size;
and this struct type
struct eventlist// Define our struct type
{
char name[100];
char todo[100];
char where[100];
char when[100];
char attended[100];
char excitement[100];
};
And I want to create a dynamic array of structs. Here is what I have as a constructor...
summerlist::summerlist()
{
size = 0;// Initialize size to zero
counter = 0;//Initialize counter to zero
pointer = new eventlist[size];
strcpy(pointer[0].name,"\0");
strcpy(pointer[0].todo,"\0");
strcpy(pointer[0].where,"\0");
strcpy(pointer[0].when,"\0");
strcpy(pointer[0].attended,"\0");
strcpy(pointer[0].excitement,"\0");
}
I am mostly curious about:
Is it okay to allocate my array of structs in my constructor? Could it cause any problems?
Is it okay to allocate the array before initializing the pointer to NULL? I am assuming it is not a big deal since I am in a way initializing it as a pointer to a dynamic array. But I want to know if it is an acceptable practice.
Does it make sense to initialize the first element of the array like the way I did? I thought since the memory is allocated for at least one element of the array (the base) it'd be a good practice to initialize the first element, but I am still a little shaky whether I am visualizing correy.
Lastly, after I created my dynamic array and I set pointer to = NULL, that would just create a memory leak, and wouldn't initialize the first element right?
Yes this is fine, in fact allocating in the constructor and deleting in the destructor is the start of RAII types which you should aim to achieve.
You are simply assigning a pointer to some memory, it does not matter what the pointer held before, it could be anything.
That depends entirely on your application.
Yes you would. You need to delete any memory you have created. I would suggest in the destructor of your class. Remember to match new[] with delete[].
As a final note, this type of code is good for learning, but bad for implementation in c++. Unless you have some form of memory restriction (which you clearly don't since you are creating a big set of dynamic stored structures) then you should switch to using some of the built in c++ types, like std::vector to replace your dynamic array, and std::string to replace your char arrays.
struct eventlist {
std::string name;
...
}
class summerlist {
public:
summerlist();
private:
std::vector<eventlist> pointer;
int counter;
}
summerlist::summerlist()
{
counter = 0;// Initialize the counter to zero
}
This is much easier to use and control. And you avoid the mistake of doing this: pointer = new eventlist[size]; where size is 0. This should save you some headache.
I need some clarification on C++ memory allocation, I'll just get right to an example
Let's say I have made a class A, which contains two containers: a hash_map and a std::vector like this:
class Example{
// methods to add stuff to containers
//...
std::hash_map<std::string,int> map;
std::vector<std::string> vec;
}
If I then create an object of example on the heap using the new operator:
Example* ex = new Example();
and add a thousand entries to each container, will the entries I add be located on the heap as well? If yes, then what would be different if I did:
class Example{
// methods to add stuff to containers
//...
std::hash_map<std::string,int>* map;
std::vector<std::string>* vec;
}
and then Example* ex = new Example();
No matter where a hash_map or vector is stored, the data that they contain will always be in the heap.
Example 1
int main() {
hash_map<T> table;
}
table is on the stack. The data that table contains is on the heap.
Example 2
int main() {
hash_map<T> *table = new hash_map<T>();
}
table is a pointer that exists on the stack. *table is a hash_map that exists on the heap. The data that *table contains is still on the heap.
Example 3
hash_map<T> table;
int main() {
...
}
table is not in the heap or stack. The data table points to is still on the heap.
The data items in both containers will always be in the heap;
The difference between having std::hash_map map and
std::hash_map *map is that in the first case your Example object holds actual object map (which, in particular, will be automatically destroyed when Example object is destroyed), while in the second case your Example object only holds a pointer to the object map (which is probably created/destroyed elsewhere).
new Example(); This statement always means allocate a single Example object on the heap and return the pointer to that object.
Example ex; is the way to allocate a single Example object on the stack.
The differences you describe are in the content of an Example object. In the first instance the object holds instances of an stl vector and a hash_map directly (they are constructed with the object and released with it)
In the second instance the object holds pointers the containers and what you put on these pointers is left open.
In any case the vector and hash_map would use the heap to store the data you insert into them, But they hide the details and the management from you. (You can supply allocators to mess with defaults )
Advanced Note:
Example ex; when in the scope of a function / method would allocate the object on the stack. The object is released when the scope exits. When used inside a namespace or global scope it would allocate the object in the data segment and the object is released when the program terminates.
In both cases, your object will be instantiated on the heap. The new operator does that.
The difference between your two examples is that in the first one, without using * for the two members, they are implicitly constructed as part of your object when you call new Example() (in memory, your object layout will contain a hash_map and a vector of sizes sizeof(hash_map) and sizeof(vector)).
In the second case, when you are declaring the members as pointers, your object layout in memory will only contains 2 sizeof(void*) - basically size of pointer, all pointers are equal in size regardless of the type they point to. This also means that, when you instantiate your class with new Example(), your members will by default be nullptr, so you have to explicitly initialize each of them with new hash_map and new vector in order to use them.
As for stack allocation, if you want an instance of your Example class to be allocated on the stack, in a function you would use
Example foo;
instead of
Example* foo = new Example();
This will allocate foo on the stack and destroy it automatically when the function returns.
Suppose in C++, I have the following code:
class Foo {
private:
double* myData;
public:
Foo(double data[]) {
myData = data;
}
}
int main() {
double mainData[] = {1.0};
Foo myfoo(mainData);
}
As far as my knowledge can tell, mainData is treated as a pointer when passed into the Foo constructor, so the line myData = data only assigns the pointer address. So no extra memory is allocated here, right? But then, is the Foo class responsible for providing a destructor that deallocates myData's memory? Or do we have a dynamic array pointer that actually points to stack memory?
Also, if I want to protect Foo's myData from changing when mainData is changed, is there a simple way to force the Foo constructor to copy it? Ideally myData would be a simple array, not a pointer, but changing the line double* myData to double myData[] doesn't seem to work because the size of the array is unknown until runtime.
The parameter here is not a dynamic array:
Foo(double data[])
In fact the declaration is equivalent to this:
Foo(double * data)
Even decltype will tell you they are the same thing, and those two signatures will conflict as overloads.
So, there is no allocation. You are only passing a pointer to the first element of the array.
Also, the only place where C++ will automatically copy an array is when it is a member of a class, and the empty bracket [] syntax for indeterminate size is not allowed for members. (Or if it is, the size is already determined by the time the class type is complete, before the copy constructor or assignment operator is generated.)
Also, if I want to protect Foo's myData from changing when mainData is changed, is there a simple way to force the Foo constructor to copy it? Ideally myData would be a simple array, not a pointer, but changing the line double* myData to double myData[] doesn't seem to work because the size of the array is unknown until runtime.
You can keep a copy of the data, but you will need a pointer if its size (or at least an upper bound) is unknown at compile time. I would recommend std::vector over a naked pointer, or at least std::unique_ptr< double[] >.
In this case myData points to an address on the stack, which calls the destructor for Foo when the function goes out of scope. Generally arrays are described as being dynamic when you use the keyword new to allocated them.
As for your second question, you're probably going to have to pass into the constructor a pointer to the array and the length of the array. You then need to dynamically create a double array (pointed to by myData), using the length that was passed in, and then make a copy.
Don't forget to delete the memory in the destructor.
A pointer only holds a memory address, without new or delete involved a pointer has nothing to do with allocation or deallocation. Thus your code wont invoke any memory allocation.
In order to delete an (dynamically allocated) array you have to do delete[] foo;
Only dynamically allocated objects must be deleted, if you class takes ownership (it manages the array, calls delete on destruction) passing an array with automatic storage duration is a very bad idea.
Yes, it does not allocate additional memory.
No, the destructor won't do anything with the class field if it hadn't been told so.
in Foo class instances will have pointer to data that is allocated/managed by other classes this is very bad design. The best thing is to make the Foo constructor make a copy and store it in the pointer. Then in the desctructor free that one. This would require passing the length of the array to the Foo constructor. I hope that helps.
For example i have class with constructor that has array of ints as parameter:
A(int* array) : m_array(array) {}
I can use it like this:
int array[] = { ... }
A a(array);
Or like this:
int* array = new int[10];
A a(array);
If object then use it array, it must (or may be not?) delete it in desctructor (if it was dynamic). But how he will know, that memory for this array was allocated dynamically?
You can't know if it's dynamically allocated or not, because after all, int* array is an int pointer, not an array. You might as well pass:
int i;
A a(&i);
As you can imagine, bad things will happen if you try to delete[] that one, or try to access m_array[N] with N > 0.
So you have to rely on the caller to do the right thing; there's nothing you can do to verify or enforce it. All you have is the address of an int. Who created that int, or how or whether more ints follow after it, will be unknown.
If you want more safety, use an std::vector. This is what it was made for.
You're initializing the array in the constructor, so it will always be initialized. It is pre-defined in the code that it will be allocated. If there are other constructors that do not allocate your array, you will need to do this check.
By the way, this is under the assumption that the array you are allocating is a member of the class. If you are assigning it to a new stack variable within the constructor, you won't be able to delete it in the destructor.
From what i understand you are trying to ask is whether the destructor will free the memory you have allocated to the array.
No, the memory you have allocated using new will have to be deleted by you either in the destructor or somewhere else the pointer is in scope as your memory allocation is not inside the constructor but outside.
You cannot know what it was because a static array decays into a pointer as well.
Basically you just need the value of the array passed to the constructor. You need not know whether it was a dynamically allocated or statically allocated array. What matters is the data member array which is part of the interface of your class and into which you are copying the data. Responsibility of the array passed to the constructor as an argument should rest with the caller regarding its deletion and lifetime.
It would make your life easier if you use std::vector instead of raw array.
class AClass
{
// ...
}
~
class AnotherClass
{
public:
// ...
void AMethod()
{
// ...
AClass * ac = new AClass(); // Dynamic memory allocation here
m_Objects.push_back(ac);
// ...
}
// ...
private:
// ...
std::vector<AClass *> m_Objects;
// ...
}
I want to add new objects of AClass to the vector m_Objects.
Is there any other way of doing this without doing dynamic memory allocation?
There are two things causing dynamic memory allocations here:
vector::push_back
new AClass()
Here is one idea how to reduce dynamic memory allocations.
First step is to call m_Objects.reserve(N); in the AnotherClass constructor, where N is the maximum number of AClass objects you want to keep at any given time. This reserves enough memory to remove the need for dynamic allocations by vector::push_back.
Second step is to make m_Objects contain objects instead of pointers, i.e. make it type std::vector<AClass> instead of std::vector<AClass*>. This allows you to skip new and directly create the new object by growing the container:
m_Objects.resize(m_Objects.size() + 1);
Now, there will be no dynamic allocation when adding a new object.
If you mean "can I create new objects at runtime without doing dynamic allocation?" then the answer is no. That's what dynamic allocation is.
If you want to create some before they're immediately needed by creating them in bulk ahead of time, then that's plausible. Simply allocate a large number and then pull them out of an array or vector as needed.
Not so long as m_Objects is a vector of pointers, unless you were to store a pointer to an automatic (stack) variable. But that, undoubtedly, would be a very bad idea.
There are only two ways to allocate objects at runtime: dynamically on the heap, and on the call stack.
It is possible to instantiate multiple objects that are local (auto) variables within a function block by calling the function recursively, and adding these stack objects to your vector. But I'm pretty sure that's not what you really want.
That means that the only other way is to use new to dynamically create the new objects.