在下面的代码中,我使用new关键字动态分配数组。在我用完范围之前,我在我的数组上调用 delete [] ,之后我将punter设置为null。
我的问题是,如果这足够,将删除[] 确保释放我阵列中所有3个Car对象的已分配内存。或者我是否必须做一些特定的事情来释放每个对象使用的内存?
void main()
{
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
此外,汽车类看起来像这样。在这里将名称设置为null也足够了。 Name是一个char指针。或者可能不需要将指针设置为null,因为它没有引用堆上的任何内容。
Car::Car(char * newName)
{
name = newName;
}
Car::~Car()
{
name = nullptr;
}
修改
首先,感谢所有出色的答案和评论。我从阅读中学到了很多东西。
现在我明白了,我需要在声明动态分配数组时指定一个大小。
除此之外,我也理解,我需要像我一样停止使用新的。我想最好把对象扔到堆栈上,让它们在某些时候超出范围。除此之外,我想我的汽车上的析构函数什么也没做。
阅读完评论和答案后,我将我的代码更改为:
int main()
{
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
答案 0 :(得分:4)
在你的情况下,你已经从你对new Car("BMW")
的调用中泄露了内存,并且丢失了指针以释放内存。
这一行:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
创建一个包含3个Car
对象的数组,然后为每个条目创建一个新的Car
对象,使用它初始化数组中的对象,然后忘记新对象。
它可以更简单地写成:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
甚至
Car * myArray = new Car[3]{ "BMW", "AUDI", "SKODA" };
在这种情况下,delete[]
足以释放使用的内存。
请注意
Car::~Car()
{
name = nullptr;
}
没有做任何事情来释放记忆。调用Car
析构函数后,没有人应该再次访问该对象的name
(事实上它是未定义的行为),因此将其设置为null没有什么意义。
编辑注意:正如R Sahu和Aslak Berby指出的,Car * myArray = new Car[]{ ... };
不是制作数组的有效方法,而是使用Car * myArray = new Car[3]{ ... };
。
答案 1 :(得分:3)
你不能使用:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
您需要指定尺寸。
Car * myArray = new Car[3]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
即便如此,请致电
delete [] myArrary;
会泄漏内存。该行相当于:
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;
该行
delete [] myArrary;
不会删除为car1
,car2
和car3
单独分配的对象。您也必须明确删除它们。
delete car3;
delete car2;
delete car1;
但是,你不能使用
Car * myArray = new Car[3];
因为Car
没有默认构造函数。您可以向Car
添加默认构造函数。如果你不能使用:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
然后,使用:
就足够了delete [] myArrary;
取消分配内存。
答案 2 :(得分:1)
是的,只有在创建Car
元素的普通数组时才足够,因为数组名是指向其第一个元素的指针
您通过指定[]
在您的情况下,您似乎正在创建汽车指针,因此您必须清理每辆汽车占用的内存位置,然后清理为整个阵列分配的内存。
您错误地尝试做的是这样但不要这样做。令人费解的
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;
看看这个讨论
答案 3 :(得分:1)
Car * myArray = new Car[X];
此代码已创建X
Car对象。你所要做的就是真正使用它们。
但是,我认为你的困惑在于:这是另一种做法
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;
此代码分配3个Car*
指针的数组。因此,您尚未创建任何Car对象,这就是您使用Car*
调用初始化每个new Car()
指针的原因,该调用实际上会创建Car对象。
答案 4 :(得分:0)
基本上,每delete
你需要delete[]
(或new
}。但是在一个更复杂的程序中,这可能非常困难(并且容易出错)以确保。
您应该学会使用shared_ptr
或unique_ptr
等智能指针,而不是原始指针。这些可以让您在大多数情况下避免使用明确的new
和delete
。
答案 5 :(得分:0)
我同意您过多地使用关键字new
的评论。
我建议改用std::vector
。
这是一个工作示例,其中类Garage
在堆/ freestore上具有Car
的向量,稍后使用析构函数~Garage
仅供说明的示例:
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();
}
使用上面的新矢量仅用于演示,不需要它。使用没有新版本的std::vector
可以更快更安全地实现此目的,您无需在使用后将其删除。
另请考虑使用智能指针而不是new
。
答案 6 :(得分:0)
您可以将对象添加到堆或堆栈中。如果将它添加到堆中,则可以随意创建它。这是使用new完成的,你得到一个指针作为回报。
Car *aCar=new Car("BMW");
如果在堆栈上创建它,则只需像使用其他变量一样定义它。
Car anotherCar("BMW");
如果在堆上创建它,则还需要从堆中释放它。这是通过删除完成的。
delete aCar;
您永远不会处理您在堆栈上创建的对象。当你超出范围时,这将自动被处理。
至于创建数组,您可以创建一个statick或dynamicall对象数组。
动力学:
Car **cars=new Car*[3];
cars[0]=new Car("BMW");
cars[1]=new Car ....
所有这些都需要单独删除。这里没有级联。
delete cars[0];
delete cars[1];
// And finaly the array.
delete[] cars;
你可以创建它们staicaly:
Car cars[]={"BWM", "AUDI"};
这次包括数组在内的所有对象都被推送到堆栈,当你超出范围时将被删除。
在两者之间你可以创建一些东西,这是一个基于堆栈的数组,指向堆分配的对象,或者像其他建议一样的堆分配的静态数组。
对于C ++,我建议使用std :: library,在这种情况下使用std :: vector;
或者:
std::vector<Car *> myArray;
myArray.push_back(new Car("BMW"));
.....
// Cleanup:
for(auto car : myArray)
delete car;
或者:
Car car;
std::vector<Car> myArray;
car.SetType("BMW");
myArray.push_back(std::move(car));
答案 7 :(得分:0)
我不确定我是如何在一篇两年前的帖子中结束的。没有一个答案确实给出了一个简单的C ++解决方案,所以这里是使用容器的60秒解决方案,而且看不到新的/删除。
#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";
}
}
答案 8 :(得分:0)
否。 delete []myArray
只会导致称为悬挂指针的东西。
这基本上意味着程序不再拥有指向的内存 myArray ,但 myArray 仍指向该内存。
为避免指针悬空,删除后将指针分配给nullptr
。
delete[]myArray;
myArray = nullptr;