I'm not sure if this is good coding practice, so please correct me if I am wrong.
I needed a way to dynamically create a Transaction class and add the object to a vector of Transaction objects. This is what I did:
class Transaction {
int data;
Transaction(int d) : data(d) {}
};
class Container {
std::vector<Transaction> transactions;
void createTransaction();
};
void Container::createTransaction() {
int data;
std::cout << "Enter your data: ";
std::cin >> data;
Transaction t = new Transaction(data);
// In order to keep the object from destruction at end of function.
// Possibly could be done with static as well.
transactions.push_back(*t);
}
The vector is a vector of objects, not pointers. Is this a case where I do not need to delete the dynamic memory, as it will delete itself upon the end of the program/scope?
Is this a terrible way to go about creating objects dynamically and storing them?
Values semantics apply : transactions.push_back(*t); will push a copy of t in your std::vector.
So you still need to delete the memory allocated for the original object : any new must be match by a call to delete.
You probably don't need a new in the first place, you can just do :
Transaction t(data);
...
transactions.push_back(t);
Note:
As pointed by Matt, Transaction t = new Transaction(data); doesn't even compile, you probably meant something like Transaction* t = new Transaction(data);
You either store plain objects OR pointer to objects in vector. You are drawing line somewhere in between as you are creating objects on heap and then stroing plain objects in vector.
Question is who would delete these objects?
By default store plain objects in vector. But if copying of objects is expensive OR there's no proper way to define copying for the objects OR you want to preserve polymorphic behavior then you store pointers into the container.
Related
I am not allowed to use Vectors specifically for this school assignment. Most of the answers I've found simply state "you should use vectors" as the most up-voted comment. While I appreciate and understand this, I'm simply restricted from using them for this assignment.
It is a C++ assignment with dynamic memory management as follows:
// property in header declaration
int numAnimals;
int capacity;
Animal** animals;
void addAnimal(Animal *newAnimal);
// class implementation
capacity = 10;
numAnimals = 0;
animals = new Animal*[capacity];
void SampleClass::addAnimal(Animal *newAnimal)
{
for (int i = 0; i < capacity; i++){
if(animals[i]){
// animal object already exists in array, move on
i++;
}else{
animals[i] = newAnimal;
numAnimals++;
break;
}
}
}
animals is a pointer to a pointer, in this case a pointer to an array of pointers to object type Animal which have yet to be created.
With the 'addAnimal' function, what I'm trying to do is add an animal object to the array by looping through the array of pointers, and if there already exists an animal object, iterate to the next index. If there is no animal, then insert that animal into the array.
I'm getting an exception thrown "read access violation" when I attempt to access a member function of an animal object in the array.
My suspicion is because:
if(animals[i]) probably isn't doing what I think it's doing, running it through the debugger I never hit the 'else' portion, so the array is still full of pointers not set to any objects when the method is complete. Therefore, when I try to access a member function, it's of an object that doesn't exist.
So, if my suspicions are correct, then what is the best way to insert a new object into an array of pointers in this fashion? They need to be pointers otherwise it automatically creates the array full of populated objects, which is not what I want.
I didn't post all of the code because I wanted to keep my problem brief, apologies I'm a new to C++ and stackoverflow in general. Yes, I know to delete[] to clear memory afterwards.
Any help is appreciated, thanks!
Since in numAnimals you keep count of the current number of animal pointers in the array, you don't need the for loop to find the first available slot to add a new animal pointer (note also that, assuming you want to use a for loop like shown in your code, you have to pay attention to properly initialize all the initial pointers in the array to nullptr).
You can just use:
// Inside SampleClass::addAnimal(Animal *newAnimal):
animals[numAnimals] = newAnimal;
numAnimals++;
Please note that you have to pay attention to not overflow your array capacity, when you insert a new animal.
So, before inserting a new animal, you have to check that there's enough room in the array, e.g.:
// Before inserting:
if (numAnimals == capacity)
{
// You ran out of capacity.
//
// 1. Allocate a new array with bigger capacity (e.g. 2X)
// 2. Copy the content from the current array to the new one
// 3. delete current array
}
As a side note:
Yes, I know to delete[] to clear memory afterwards
Note that if you call delete[] on the animals array of pointers, you release this pointer array, but not the Animal objects pointed to.
int capacity = 10;
Animal** animals = new Animal*[capacity];
This allocates ten pointers, except it does no initialization,
meaning you have essentially garbage data.
if (animals[i])
This test one of those pointers against nullptr, but since you did
no initialization, it's not very likely that it's nullptr.
You need to add a loop-pass that null out the data, right after you
allocate it:
for(int i=0; i<capacity; ++i)
animals[i] = nullptr;
There is also a bug:
if (animals[i]) {
// animal object already exists in array, move on
i++; // <- here
This is wrong, you move on twice for (int i = 0; i < capacity;i++)
The thing is "Use a vector", despite your teacher telling you otherwise, is the correct way to do it. However, if you are supposed to manage the dynamic array manually, then the best you can do is to encapsulate all that dirty memory stuff inside a class and write your own replacement for std::vector. Ie to avoid having dynamic allocations spread all over your code (especially in places that are supposed to deal with Animals and shouldnt care about manually allocating memory and the like) you should write a class that does that (and nothing else) and provides a nicer interface. I can only outline the idea here:
template <typename T>
class my_vector {
private:
T* data;
size_t size;
size_t capacity;
public:
void push_back(const T& t);
size_t size();
T& operator[](size_t index);
void resize(size_t size);
//... etc...
};
I'm writing a program in C++ that has to use dynamically allocated arrays from various structures (in separate files). A lot of times, I need to initiate these arrays inside of a function. Usually after initiating them, I write data to the array of a structure, or even an array inside of an array of structures, and then use the data later on. Therefore I don't use delete inside of the function.
For example, here is one of the structures that I use, a student structure:
struct Student {
int id; // student ID
char gradeOption; // either G or P
double totalScore;
std::string studentName;
int* rawScores = NULL; // array that holds raw scores for a student
// if no scores are entered for a specific ID, we check for NULL
// we can then set the scores to 0
std::string* finalGrade; // final grade given in course
};
And here is the function to input raw scores.
// input raw scores for each id
void inputRawScores(int gradedArtifacts, int id, Student* student) {
student[id].rawScores = new int[gradedArtifacts];
for(int i = 0; i < gradedArtifacts; i++) {
std::cin >> student[id].rawScores[i];
}
}
In my driver file, students also gets initialized with a value. Shown here:
Student* students = new Student[numOfStudents]; // array of students
The problem is is that I use these raw scores, and the array of students for calculations in a separate file, and use them for output in other files, and in other methods. How would I go about deleting any of these?
Also I realize that using delete will delete the structure and the pointers inside of the structure, but not the objects that the pointers point to. So I'm assuming this ties back into the first question and I can't just issue a delete at the end of my program.
Edit: I'm sorry, as many others have pointed out I should have stated the restraints that I have on the project. I'm not allowed to uses: classes, vectors, functions inside of structs (like constructors, destructors).
Don't do that.
Your system is badly designed, your struct should be a class and internally handle the rawScores memory - using a std::vector would be the easiest part, but even if you use regular pointers, the key is that the information about how many there are, and where they are stored, should be tracked in a class.
In other words, the student structure should keep track of HOW MANY elements there are, and allocate/deallocate the memory as needed. It should not be done in the function inputRawScores - that function may well call the function for setNumRawScores and call the function for setRawScore(n, value), but not allocate memory in the reader function. That belongs as a member function in the student structure. Then introduce a destructor method for your student, that is responsible for deallocating the memory.
Of course, using std::vector will "hide" all this from you, and you just have to set the size (or use push_back).
Given your newly posted constraints, I think you could just implement a deletion-function to traverse through the Student array and do manual cleanup.
First, we create a function that deletes the dynamic objects of one single student. Note that we could have used Student&as the parameter type, but given the information in your question I am not sure if you have learned references yet, or if you are allowed to use them. So we stick with the pointer:
void cleanupStudent(Student* student) {
delete[] student->rawScores;
delete student->finalGrade;
// EDIT: Setting pointers back to NULL after deletion provides
// some improved safety and is good practice.
student->rawScores = NULL;
student->finalGrade = NULL;
}
After that we create a function that allows you to delete the complete Student array by looping through all the items in the array and calling the cleanup function:
void deleteStudents(Student* students, int studentCount) {
for(int i = 0; i < studentCount; i++) {
cleanupStudent(&students[i]);
}
delete[] students;
}
Here, please note the ampersand-symbol (&students[i]) which we require to get a pointer to the object (which is required as a parameter to the cleanup function). After that, the student array itself is deleted.
You can call these functions like this:
int numOfStudents = 16;
Student* students = new Student[numOfStudents];
deleteStudents(students, numOfStudents);
Or with a single student:
Student* student = new Student;
cleanupStudent(student);
delete student;
As you might have noticed we sometimes use delete and sometimes delete[]. The first one just deallocates memory that has been allocated with new. The latter does the same thing to memory that has been allocated with new[]. This is very important to get right, otherwise you will get runtime errors. Also, make always sure that EVERY pointer in your struct is initialized wih NULL (C) or nullptr (C++).
Since it seems that you are just learning C/C++ it is crucial to mention that the above code is very unsafe, and you could get into real problems if e.g. the studentCount is not matching the actual number of items in the array. But for now I guess you wouldn't know (or aren't allowed) to do better.
EDIT: I noticed that your finalGrade member is of type std::string*. Is there a reason for this to be a pointer? Because if you just want to store a string, you can just do a std::string, no reason there to be a pointer. Please don't confuse a C-String of type char* with a STL string std::string.
This answer is obsolete since the owner of this questions specified some constraints that do not allow constructors/destructors.
As far as I unterstand your question, you do not know how to delete the actual dynamically allocated rawScores and finalGrad objects in your Student object, right? If so, the answer is quite simple, you just use a Destructor:
struct Student {
int id; // student ID
char gradeOption; // either G or P
double totalScore;
std::string studentName;
int* rawScores = nullptr;
std::string* finalGrade = nullptr;
// Disable copy and move assignment
Student& operator=(const Student& rhs) = delete;
Student& operator=(Student&& rhs) = delete;
// Disable copy and move construction
Student(const Student& rhs) = delete;
Student(Student&& rhs) = delete;
Student() {
// Initialize members.
}
// Destructor
~Student() {
delete[] rawScores;
delete finalGrade;
}
};
As soon as you deallocate a Student object using the delete operator:
Student* students = new Student[numOfStudents];
delete[] students; // <-- deallocation
The destructor is called for each object, which in turn will delete the dynamically allocated objects inside.
You don't have to bother if the pointers are NULL or not, calling delete on a pointer that is NULL is valid. Also, please initialize ALL pointers initially with nullptr when constructing the object (as shown above).
As long as you are not mixing runtimes accross different EXE/DLL boundaries you can delete the Student array from anywhere in your program, not matter in which file you allocate/deallocate it.
I hope this answers your question. If not, please be more specific about the problem you have.
EDIT: As pointed out in the comments, you should disable copy/move semantics if you are doing it this way (or implement them). But disabling them would practically pin you to dynamic allocation of the Student struct and give you less flexibility with most of the STL containers. Otherwise you could also use an std::vector instead of dynamically allocated arrays as pointed out in the other anwers.
It would be very tedious to effectively delete everything you hve allocated using new in this case as you are passing pointers to other modules/functions.
You have two options over here:-
Either replace those dynamic arrays ( rawscores/finalGrade ) with corresponding vectors.
You can use smart pointers ( I think auto_ptr would suffice if you are not using containers ) to take care of memory mangement.
EDIT:-
One main issue you have to handle if you are creating raw student pointer is of ownership. Let's say you have allocated memory to Student* and then you are passing this object to several modules/functions. You need to take into account that you don't call delete when your pointer is still in use in some other module. Also it should also not call delete when it's already deleted in some module. That's why I pointed you to two options...
I have read a lot about vector of pointers on this forum but have trouble grasping the idea of deleting the pointers stored in the vector. Following is my query:
Suppose I dynamically create an array of objects
CPoint* dynamic_array;
dynamic_array = new CPoint[30714];
I now have to use these values in object of another class through vector of pointers
vector<CPoint*> vector_of_pointers;
I will then divide the elements of dynamic_array into objects of another class using the following
Class B{
vector<CPoint*> vector_of_pointers;
public:
void function(CPoint* a){
if (some condition){
vector_of_pointers.push_back(a);
}
};
Where a will always be a pointer to object from dynamic_array
I then plan to delete the originally created dynamic_array, after the need for its objects is over.
delete[] dynamic_array;
Is deleting each pointer in the vector necessary even after doing this? And if it is necessary can I do it in the destructor for Class B?
Sorry if this is a simple or silly question but I am newbie in c++ and using a container is necessary for my application.
To answer your original question: No, you don't need to delete individual CPoint objects (in fact you can't).
But I do believe that you'd be better off using vector<CPoint> to store the actual point, rather than a pointer to it.
The pointers that you store in your vector<CPoint*> point to objects that you already deleted with your delete[] dynamic_array instruction, so you don't have to, and also should not, add delete instructions on the individual pointers stored in your vector.
Is deleting each pointer in the vector necessary even after doing this? And if it is necessary can I do it in the destructor for Class B?
The answer is no and in fact you can't.
Whether or not it is better to just use std::vector I think it depends on your needs but I can confirm that using new[] is a lot faster than creating each object separatelly. Some times:
class CPoint {
public:
float x; float y;
}
const int N = 1e6;
for(int i = 0; i < N; ++i)
{
new CPoint();
}
// 122 ms
CPoint* points = new CPoint[N];
// 0.00793176 ms
std::vector<CPoint*> vectorPoints(N); // same as above
// 4.48263 ms
Using std::vector<CPoint*>(N) is also fast but not faster as new[]
deleting CPoint objects pointed by pointers in the vector is not necessary and is impossible but the pointers in the vector must be removed from the vector.
you must clear the vector because it holds at least 4*number_of_elements(8*number_of_elements in x64 systems) of useless pointers.
I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);
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").