Reputation: 63
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;
}
Upvotes: 0
Views: 6393
Reputation: 1303
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;
Upvotes: 0
Reputation: 1135
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";
}
}
Upvotes: 0
Reputation: 8514
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.
Upvotes: 4
Reputation: 183
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));
Upvotes: 0
Reputation: 11028
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
.
Upvotes: 0
Reputation: 1950
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
Upvotes: 1
Reputation: 206727
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.
Upvotes: 3
Reputation: 3527
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.
Upvotes: 1
Reputation: 9396
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.
Upvotes: 0