Free the memory of a pointer to a struct - c++

I am new to C++ and implemented the following struct:
struct Person {
String name;
int age;
};
Now I create a new object:
Person *p = new Person();
p->name = "name";
p->age = 211;
and push it onto a stack:
stack.push(*p);
I have a while(!stack.empty()) expression and in there I process every element I pushed onto the stack.
Now where do I free the memory? In the while-loop I do the following:
Person *current = &stack.front();
stack.pop();
// do stuff
delete current;
Sadly, the delete current statement throws some kind of exception.
What do I do wrong? Thanks for your help.

You would need to delete p after pushing into the stack. The stack stores its own copy of the object pushed into it, so there is no need to do anything to it after popping.
But the real solution is to not use new in the first place:
Person p = {"name", 211};
...
stack.push(p);
or just
stack.push(Person{"name", 211});
Then
Person current = stack.front();
stack.pop();
So, no need to deal directly with memory management.

When you push something on to a stack, you don't push the original object - you push a copy of the object. To free the memory of the original object, you need to do it right at the point after you've pushed it.
Or you can skip that altogether and don't use new to create the object in the first place:
Person p;
p.name = "name";
p.age = 211;
stack.push(p);

You don't need to make a pointer. If you have to, then use a smart pointer to free the memory for you: std::unique_ptr<Person> p(new Person);

Related

Make instance of class on existing variable

How i can make c++ instance on existing variable
This is my header:
#ifndef PERSON_H_
#define PERSON_H_
class Person{
private:
std::string name = "default";
public:
void setName(std::string name);
}
#endif
This is my person.cpp
#include "person.h";
void setName(std::string name){
this->name=name;
}
And my main cpp file
#include <iostream>
int main(){
Person p;
p.setName("Jack");
//so person now have name Jack.
//here is my problem
p=new Person;
//get error.So how i can on variable p make new instance of Person for return all to default values
return 0;
}
p = Person();. In most cases p = {}; will also work.
new gives you a pointer to a new instance of Person. A HolyBlackCat pointed out, you are not using a pointer here. So either use p = Person() or go with pointers from the very beginning with Person *p = new Person(). However, in this case, I really do not see any need for pointers.
Person* p = new Person(); If you do want to make a new instance use pointer of type Person which will point to the memory address allotted by the new operator. Do whatever operation you want to perform. Since you are using new, make sure to use a delete operator to prevent memory leaks.delete p; delete will basically delete the value at the address pointed by p and assign a nullptr to it so that it doesn't become a dangling pointer. Then again if you want to assign new instance you can use the new operator. Now will p point to a different memory location which is the address of the new object.
-Person *p = new Person();
//perform operations
delete p;
p = new Person();

C++ Is delete[] enough to clean up after an array?

In the code below I'm allocating an array dynamically by using the new keyword. Before I run out of scope I call delete[] on my array, and afterwards I set the punter to null.
My Question is, if this is enough, will delete[] make sure that the allocated memory for all 3 Car objects in my array is released. Or do I have to do something specific to release the memory used by every single object?
void main()
{
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
Also, the car class looks like this. Is it also enough to set the name to null here. Name is a char pointer. Or maybe it isn't needed to set the pointer to null since it isn't referencing anything on the heap.
Car::Car(char * newName)
{
name = newName;
}
Car::~Car()
{
name = nullptr;
}
EDIT:
First of all, thanks for all the great answers and comments. I learned a lot from reading them.
Now I understand, that I need to specify a size when declaring a dynamic allocated array.
Besides that I also understand, that I need to stop using new as much as I do. I guess its better to throw the objects on the stack, and let them go out of scope at some point. Besides that I guess my destructor on my car does nothing.
After reading the comments and the answers, I'v change my code to this:
int main()
{
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
In your case, you have already leaked the memory from your calls to new Car("BMW") and have lost the pointer to be able to free the memory.
This line:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
Creates an array of 3 Car objects, then for each entry it creates a new Car object, uses it to initialize the object in the array, then forgets about the new object.
It can be more simply written like this:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
or even
Car * myArray = new Car[3]{ "BMW", "AUDI", "SKODA" };
In which case your delete[] is enough to free up the memory used.
Note that
Car::~Car()
{
name = nullptr;
}
does not do anything to free memory. Once the Car destructor is called, no one should be accessing name for that object again (in fact it is undefined behavior), so there is little point in setting it to null.
Edit Note: As pointed out by R Sahu and Aslak Berby, Car * myArray = new Car[]{ ... }; is not a valid way to make an array, use Car * myArray = new Car[3]{ ... }; instead.
You cannot use:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
You need to specify a size.
Car * myArray = new Car[3]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
Even after that, calling
delete [] myArrary;
is going to leak memory. That line is equivalent to:
Car * myArray = new Car[3];
Car* car1 = new Car("BMW");
Car* car2 = new Car("AUDI");
Car* car3 = new Car("SKODA");
myArray[0] = *car1;
myArray[1] = *car2;
myArray[2] = *car3;
The line
delete [] myArrary;
does not delete the objects allocated separately for car1, car2, and car3. You'll have to explicitly delete those too.
delete car3;
delete car2;
delete car1;
However, you cannot use
Car * myArray = new Car[3];
since Car does no have a default constructor. You can add a default constructor to Car. Failing that you can to use:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
Then, it is sufficient to use:
delete [] myArrary;
to deallocate the memory.
Car * myArray = new Car[X];
This code already creates X Car objects. All you have to do is use them really..
However, I think your confussion lies here: this is another approach to do it
Car ** myArray = new Car*[3] { new Car("BMW"), new Car("AUDI"), new Car("SKODA") };
for (int i = 0; i < 3; i++)
delete myArray[i];
delete[] myArray;
This code allocates an array of 3 Car* pointers. Therefore, you have not created any Car object yet, which is why you initialize each Car* pointer with with a new Car() call, which actually creates the Car object.
yes it is sufficient only if you are creating a plain array of Car elements since an array name is a pointer to its first element
You are informing the compiler that its an array by specifying the []
In your case you seem to be creating car pointers so you have to clean up the memory location occupied by each car and then the memory allocated for the whole array.
What you incorrectly attempted to do is this but don't do it. Its convoluted
Car** cararrptr = new Car*[3];
cararrptr[0] = new Car("win");
cararrptr[1] = new Car("lin");
cararrptr[2] = new Car("ios");
//now to clean up
delete cararrptr[0];
delete cararrptr[1];
delete cararrptr[2];
delete[] cararrptr;
Take a look at this discussion
delete[] an array of objects
Basically you need a delete (or delete[]) for every new. But in a more complex program this can be very difficult (and error prone) to assure.
Instead of raw pointers you should learn to use smart pointers like shared_ptr or unique_ptr. These let you avoid explicit new and delete in most cases.
I agree with the comments that you are using the keyword new too much.
I suggest using std::vector instead.
Here is a working example where the class Garage has a vector of Car's on the heap/freestore and later deleting it with destructor ~Garage
Example for illustration only:
class Car {
Car();
string m_name;
public:
Car(const string &);
void print();
};
Car::Car(const string &s) : m_name{s} { }
void Car::print()
{
cout << m_name << endl;
}
class Garage {
string m_name;
vector<Car> *m_cars; // for allocating on heap
public:
Garage(const string &);
~Garage();
void add(const Car &);
void print();
};
// Creating a new vector on heap
Garage::Garage(const string &s) : m_name{s}, m_cars{new vector<Car>} { }
Garage::~Garage()
{
delete m_cars; // deleting the vector.
}
void Garage::add(const Car &c)
{
m_cars->push_back(c);
}
void Garage::print()
{
for (auto car : *m_cars)
car.print();
}
int main()
{
Garage garage{"Luxury garage"};
garage.add(Car("BMW"));
garage.add(Car("Audi"));
garage.add(Car("Skoda"));
garage.print();
}
Using new vector above is only for demonstration, it's not needed. Using a std::vector without new is faster and safer for this purpose and you won't need to delete it after use.
Also consider using Smart Pointers instead of using new.
You can add a object to the heap or the stack. If you add it to the heap you create it dynamicaly as you go. This is done using new and you get a pointer in return.
Car *aCar=new Car("BMW");
If you create it on the stack, you will just define it as you do with other variables.
Car anotherCar("BMW");
If you create it on the heap, you also need to deallocate it from the heap. This is done with delete.
delete aCar;
You never dealocate a object you created on the stack. That will automtically be dealocated when you go out of scope.
As for creating a array, you can create a array of statick or dynamicall objects.
Dynamical:
Car **cars=new Car*[3];
cars[0]=new Car("BMW");
cars[1]=new Car ....
All of those need to be deleted seperatly. No cascading here.
delete cars[0];
delete cars[1];
// And finaly the array.
delete[] cars;
You can create them staicaly:
Car cars[]={"BWM", "AUDI"};
This time all the objects including the array is pushed to the stack and will be deleted when you go out of scope.
In between you can create stuff that is a stackbased array that points to heap allocated objects, or a heapallocated static array as other suggest here.
As for C++ I would suggest using the std:: library and in this case std::vector;
Either:
std::vector<Car *> myArray;
myArray.push_back(new Car("BMW"));
.....
// Cleanup:
for(auto car : myArray)
delete car;
Or:
Car car;
std::vector<Car> myArray;
car.SetType("BMW");
myArray.push_back(std::move(car));
I am not sure how I ended up here on a two year old post. None of the answers really give a simple C++ solution so here is a 60 second solution using containers and no new/delete in sight.
#include <iostream>
#include <string>
#include <vector>
struct Car {
// Allows implicit conversion from char *
Car(const char *manufacturer) : manufacturer_(manufacturer) {}
std::string manufacturer_;
};
int main() {
std::vector<Car> cars{ "BMW", "AUDI", "SKODA" };
for (const auto& car : cars) {
std::cout << car.manufacturer_ << "\n";
}
}
live demo
No. delete []myArray Will merely result in something called a dangling pointer.
Which basically means that the program no longer owns the memory pointed to
myArray, but myArray still points to that memory.
To avoid dangling pointers assign your pointer to nullptr after deletion.
delete[]myArray;
myArray = nullptr;

new dynamic allocation vs normal allocation

what's the difference between these two methods?
Method(CustomClass t)
{
CustomClass *temp = &t;
}
called like this
Method(CustomClass(1,2,3));
and
Method(CustomClass* t)
{
CustomClass *temp = t;
}
called like this
Method(new CustomClass(1,2,3));
i haven't coded in c++ for a few years now and am having some trouble remembering. I'm coming from c# where every class need to be dynamically allocated with 'new'. The thing is that i don't undertand the difference between alocating an object dynamically with 'new' and calling it normally. How does temp differ in the 2 examples?
More specific example: I was creating a linked list and for my list i had this method:
void List::AddNew(TestClass node)
{
if (!first)
{
first = &node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = &node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
where first and last are TestClass *; the list wasn't initialized correctly (first and last pointed to the same value) and i had no idea why, so i changed the method to this:
void List::AddNew(TestClass* node)
{
if (!first)
{
first = node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
and now it works. I'm missing a basic principle for pointers and i can't seem to guess that it is.
Here is TestClass also:
class TestClass
{
public:
int x, y;
TestClass *next;
TestClass *prev;
TestClass();
TestClass(int,int);
~TestClass();
};
what's the difference between these two methods?
One of them is using stack (automatic) allocation, while the other is using heap (dynamic) allocation.
Method(CustomClass(1,2,3)); // stack based
Method(new CustomClass(1,2,3)); // heap based
If you're going to use new you need to make sure you delete that reference also. Otherwise, you'll have a memory leak.
yes, i know this but what's the real defference between the
allocations and when should i use one or the other?
Object lifetime. If you put something on the stack, you will only be able to use it within a particular function, and any functions below it will need it passed as a parameter. If you put it on the heap, you can return a reference to it and use it wherever you want. You can't return a reference / address to a stack variable since it's life ends when the function returns.
I think you're most confused about when to use dynamic-allocation vs when to use stack-allocation. The only thing to know is that you should use stack-based allocation when there is no need for dynamic-based allocation. When is dynamic- (or heap) allocation needed you ask? Well, normally you would use it when you need an object to exist beyond the scope in which it was created or when the contents of that dynamically-allocated object rely on a strictly runtime mechanism (like the addition of elements to a vector (the size may not be known at compile-time)). Also, this...
T* t = &t;
Is not heap-allocation. This is simply a pointer with automatic-storage duration (on the stack) pointing to another object on the stack (if t is itself stack-based). Allocation on the heap happens only when new is used.
CustomClass *temp;
temp is only a pointer. It points to NULL(ok, actually it can point everywhere, but you should set it to NULL if no object exists) or to a already existing class.
CustomClass tmp;
Creates a object.
Method(CustomClass* t):
Demands for a already existing Object (t = pointer to existing object).
CustomClass *temp = t;
Assigns the pointer to a new local pointer.
Method(CustomClass t):
Should create a copy of the class you pass (not sure...)
CustomClass *temp = &t;
& = Adress-Operator. Retrieves address of t and saves it to the local pointer temp.
mfg

allocate memory and before delete the allocation define NULL

I would like to ask if I's correct the following :
MyClass *obj = new MyClass();//allocate memory
obj.Variab="HELLO";
obj=NULL;
delete obj; //free memory
Is the memory allocated for obj deleted after the last two sentences? Appreciate.THX
I would like to mention that I am working in c++ /Ubuntu. G++ is the compiler
EDIT:
What if I have?
int i=0;
list<string>l;
while (i<100)
{
MyClass *obj = new MyClass();//allocate memory
obj->Variab="HELLO";
//add the obj.valie in a list
l.push_back(obj);
i=i+1;
delete obj; //free memory
}
it is ok?
no, you should use delete before assigning to NULL
delete obj; //free memory
obj=NULL;
this is becasue the actual parameter to delete is the address of the allocated memory, but if you assign NULL before delete is used, you are actually passing NULL to delete, and nothing will happen, and you will get yourself a memory leak.
your edit question:
this code will not compile, as obj is not defined outside the while scope, in any case, also, l is a list<string> and you are trying to insert MyClass* types,this will result in another compilation error. also, you should use obj->Variab and not obj.Variab, since obj is a pointer.
EDIT to EDIT:
well, you still got a compilation error, since obj is not defined when you are trying to delete it. try this:
#include <iostream>
#include <list>
using namespace std;
class MyClass {
public:
string Variab;
};
void myfunction (const string& s) {
cout << " " << s;
}
int main()
{
int i=0;
list<string>l;
while (i<100) {
MyClass *obj = new MyClass();//allocate memory
obj->Variab="HELLO";
l.push_back(obj->Variab);
i=i+1;
delete obj; //free memory
}
for_each (l.begin(), l.end(), myfunction);
}
This not correct:
obj = NULL; // don't do that!
delete obj;
When you assign NULL to obj, you're losing the address it contained before, leaking the memory. When you then delete obj, you are deleting NULL, which is well-defined - as doing nothing.
As others have said,
delete obj;
obj = NULL;
is the common pattern to do that.
However, I consider it an anti-pattern.
Whenever you are tempted to assign NULL to a pointer after deleting its content, ask yourself: Why is this pointer still in scope? Are you sure you still need it?
It's much better to simply let a pointer fall out of scope once it's done.
Whenever you are doing
resource r = acquire();
use(r);
free(r);
(with memory/dynamically allocated objects being the most common resource), alarm bells should go off. What if use(r) fails with an exception?
Never use naked, dumb pointers. Better read about RAII and smart pointers.
This would leak, delete will not clean up what you allocated with new. Change the order:
delete obj;
obj = NULL; // I would avoid this.
Setting obj to null does not free the memory you allocated. The memory becomes no longer assigned to a variable but is still reserved, and results in a memory leak. Calling delete on a null pointer will have no effect. After the memory has been freed, the pointer becomes invalid and it is good practice to assign it to null. You need to switch the order of the last 2 statements:
delete obj; //free memory first
obj=NULL; //Set pointer to null for safety
You have to delete the very same address as was returned by new - so you have to first delete, then set to null.
Setting pointer to null doesn't affect allocation - you just overwrite the address stored in the pointer and can't access the object anymore (which implies you can't delete the object and have it leaked).

How to free memory of dynamic struct array

As someone who never dealt with freeing memory and so on, I got the task to create a dynamic array of struct and create functions to add or delete array elements. When deleting I have to free the memory which is no longer necessary.
when deleting the 2nd element of an array of the size of 3, I move the 3rd element to the 2nd position and then delete the last one. When deleting the last one, I always get an error... Is there anyone who can find an solution for me?
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend* friendList = new myFriend[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = *tempFriend;
friendList[1] = *tempFriend2;
friendList[2] = *tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete &(friendList[2]); //and delete 3rd element to free memory
}
Why did you create temporary variables? They're not even needed.
If you use std::vector and std::string, the problem you're facing will disappear automatically:
std::vector<myFriend> friendList(10);
friendList[0]->number=1;
friendList[0]->name = "ABC";
friendList[1]->number=2;
friendList[1]->name = "XYZ";
friendList[2]->number=3;
friendList[2]->name = "123";
To make it work, you should redefine your struct as:
struct myFriend {
int number;
std::string name;
std::vector<std::string> hobbys;
};
If you're asked to work with raw pointers, then you should be doing something like this:
struct Friend
{
int number;
char* name;
};
Friend * friends = new Friend[3];
friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");
//similarly for other : friends[1] and friends[2]
//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;
delete [] friends; //and finally this!
And if you do any of the following, it would be wrong, and would invoke undefined behavior:
delete friends[2]; //wrong
delete &(friends[2]); //wrong
It is impossible to delete a subset from array allocated by new []
myFriend* friendList = new myFriend[10];
You have a single whole array
+------------------------------------------------------------------+
| friendList[0] | friendList[1] | ..... | friendList[9] |
+------------------------------------------------------------------+
You can not delete &(friendList[2]).
You get from C++ whole array of 10 elements.
This array starts from friendList (or &(friendList[0])).
operator delete with pointer to the address returned by new (i.e. friendList) is valid
only.
Two things I noticed. (1) You are apparently supposed to "create functions to add or delete elements" but you haven't done that, you have only created one function. (2) You are making your work harder than it needs to be by using a struct that also needs to manage memory. I suggest you use a simpler struct.
Your assignment is, in effect, to make a simple 'vector' class, so I suggest that you do that. Start with a struct that is empty. If the teacher requires you to use the myFriend struct as written, you can add that in after you finish making your vector like functions. I'm going to assume that you aren't allowed to make a class yet because most instructors make the mistake of leaving that until last.
struct MyStruct {
int value; // start with just one value here. Dealing with pointers is more advanced.
};
MyStruct* array;
int size;
int capacity;
void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'
// I leave the functions for you to implement, it's your homework after all, but I give some clues below.
void addMyStruct(MyStruct& value) {
// First check that there is enough capacity in your array to hold the new value.
// If not, then make a bigger array, and copy all the contents of the old array to the new one.
// (The first time through, you will also have to create the array.)
// Next assign the new value to array[size]; and increment size
}
void removeMyStructAtPosition(int position) {
// If the position is at end (size - 1,) then simply decrement size.
// Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
// from position to the end of the array.
}
int main() {
// test your new class here.
// don't forget to delete or delete [] any memory that you newed.
}
The array size is fixed at 10, so you don't need to delete any elements from it. But you do need to delete the name and hobbys elements of friendList[1] (and before you overwrite it). There are two problems here:
You are setting friendList[0]->name = "ABC"; Here, "ABC" is a constant zero-terminated string somewhere in memory. You are not allowed to delete it. So you have to make a copy.
You want to delete hobby[i] whenever it was assigned. But in your code, you can't tell whether it was assigned. So you have to set every element to 0 in the constructor, so that you will later know which elements to delete.
The proper place to delete these elements is in myFriends's destructor.
It seems the point of the question is to manage a dynamic array. The main problem is that he is using an array of friendList. Use an array of pointers to friendList:
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend** friendList = new myFriend*[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = tempFriend;
friendList[1] = tempFriend2;
friendList[2] = tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete friendList[2]; //and delete 3rd element to free memory
}
But everybody else is right -- there are major issues around memory allocation for both 'hobbys' and for 'name' that you need to sort out separately.
To do your homework I'd suggest to learn much more about pointers, new/delete operators, new[]/delete[] operators (not to be confused with new/delete operators) and objects creation/copying/constructors/destructors. It is basic C++ features and your task is all about this.
To point some directions:
1) When you dynamically allocate the object like this
MyType* p = new MyType;
or
MyType* p = new MyType(constructor_parameters);
you get the pointer p to the created object (new allocates memory for a single object of type MyType and calls the constructor of that object).
After your work with that object is finished you have to call
delete p;
delete calls the destructor of the object and then frees memory. If you don't call delete your memory is leaked. If you call it more than once the behavior is undefined (likely heap corruption that may lead to program crash - sometimes at very strange moment).
2) When you dynamically allocate array like this
MyType* p = new MyType[n];
you get the pointer p to the array of n created object located sequentially in memory (new[] allocates single block of memory for n objects of type MyType and calls default constructors for every object).
You cannot change the number of elements in this dynamic array. You can only delete it.
After your work with that array is finished you have to call
delete[] p; // not "delete p;"
delete[] calls the destructor of every object in the array and then frees memory. If you don't call delete[] your memory is leaked. If you call it more than once the behavior is undefined (likely program crash). If you call delete instead of delete[] the behavior is undefined (likely destructor called only for the first object and then attempt to free memory block - but could be anything).
3) When you assign the struct/class then operator= is called. If you have no operator= explicitly defined for your struct/class then implicit operator= is generated (it performs assignment of every non-static member of your struct/class).