C++ 是否足以在数组后清理 delete[]?
C++ Is delete[] enough to clean up after an array?
在下面的代码中,我使用 new 关键字动态分配一个数组。在 运行 超出范围之前,我在我的数组上调用 delete[],然后我将下注者设置为 null。
我的问题是,如果这足够了,delete[] 是否会确保释放我数组中所有 3 个 Car 对象的分配内存。还是我必须做一些特定的事情来释放每个对象使用的内存?
void main()
{
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
另外,车子class长得像这样。是不是这里把name设置为null也够了。名称是一个字符指针。或者可能不需要将指针设置为 null,因为它没有引用堆上的任何内容。
Car::Car(char * newName)
{
name = newName;
}
Car::~Car()
{
name = nullptr;
}
编辑:
首先,感谢所有精彩的回答和评论。我从中学到了很多。
现在我明白了,我需要在声明动态分配数组时指定一个大小。
除此之外,我也明白,我需要尽可能多地停止使用 new。我想最好将对象扔到堆栈上,然后让它们在某个时候超出范围。除此之外,我想我车上的析构函数什么也没做。
阅读评论和答案后,我将代码更改为:
int main()
{
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
在您的情况下,您已经从对 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]{ ... };
。
是的,仅当您创建 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;
看看这个讨论
delete[] an array of objects
您不能使用:
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;
释放内存。
基本上每个 new
都需要一个 delete
(或 delete[]
)。但在更复杂的程序中,这可能很难(并且容易出错)确保。
你应该学会使用像 shared_ptr
or unique_ptr
这样的智能指针而不是原始指针。在大多数情况下,这些可以让您避免显式 new
和 delete
。
Car * myArray = new Car[X];
此代码已创建 X
个汽车对象。您所要做的就是真正使用它们..
但是,我认为您的困惑在于:这是另一种方法
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 对象,这就是为什么您使用 new Car()
调用初始化每个 Car*
指针,这实际上创建了 Car 对象。
我同意您过多使用关键字 new
的评论。
我建议改用 std::vector
。
这是一个工作示例,其中 class Garage
在 heap/freestore 上有一个 Car
的向量,然后使用析构函数 [=15= 删除它]
示例仅供说明:
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();
}
上面使用new vector只是为了演示,不需要。为此,使用不带 new 的 std::vector
更快更安全,并且您无需在使用后删除它。
同时考虑使用智能指针而不是 new
。
您可以将对象添加到堆或栈中。如果将它添加到堆中,则可以随时动态创建它。这是使用 new 完成的,你会在 return.
中得到一个指针
Car *aCar=new Car("BMW");
如果您在堆栈上创建它,您只需像定义其他变量一样定义它。
Car anotherCar("BMW");
如果在堆上创建,还需要从堆中释放。这是通过删除完成的。
delete aCar;
您永远不会释放在堆栈上创建的对象。当您超出范围时,它将自动解除分配。
至于创建数组,您可以创建静态或动态对象数组。
动态:
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;
您可以稳定地创建它们:
Car cars[]={"BWM", "AUDI"};
这次包括数组在内的所有对象都被压入栈中,当你超出范围时将被删除。
在这两者之间,您可以创建指向堆分配对象的基于堆栈的数组,或此处其他建议的堆分配静态数组。
至于 C++,我建议使用 std:: 库,在这种情况下 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));
我不确定我是怎么和一个两岁的孩子在一起的 post。 None 的答案确实给出了一个简单的 C++ 解决方案,所以这里是一个使用容器的 60 秒解决方案,看不到 new/delete。
#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";
}
}
不。 delete []myArray
只会导致称为 悬挂指针的东西.
这基本上意味着程序不再拥有指向的内存
myArray,但是 myArray 仍然指向那个内存。
为避免悬空指针,请在删除后将指针分配给 nullptr
。
delete[]myArray;
myArray = nullptr;
在下面的代码中,我使用 new 关键字动态分配一个数组。在 运行 超出范围之前,我在我的数组上调用 delete[],然后我将下注者设置为 null。
我的问题是,如果这足够了,delete[] 是否会确保释放我数组中所有 3 个 Car 对象的分配内存。还是我必须做一些特定的事情来释放每个对象使用的内存?
void main()
{
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
另外,车子class长得像这样。是不是这里把name设置为null也够了。名称是一个字符指针。或者可能不需要将指针设置为 null,因为它没有引用堆上的任何内容。
Car::Car(char * newName)
{
name = newName;
}
Car::~Car()
{
name = nullptr;
}
编辑:
首先,感谢所有精彩的回答和评论。我从中学到了很多。
现在我明白了,我需要在声明动态分配数组时指定一个大小。
除此之外,我也明白,我需要尽可能多地停止使用 new。我想最好将对象扔到堆栈上,然后让它们在某个时候超出范围。除此之外,我想我车上的析构函数什么也没做。
阅读评论和答案后,我将代码更改为:
int main()
{
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
在您的情况下,您已经从对 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]{ ... };
。
是的,仅当您创建 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;
看看这个讨论
delete[] an array of objects
您不能使用:
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;
释放内存。
基本上每个 new
都需要一个 delete
(或 delete[]
)。但在更复杂的程序中,这可能很难(并且容易出错)确保。
你应该学会使用像 shared_ptr
or unique_ptr
这样的智能指针而不是原始指针。在大多数情况下,这些可以让您避免显式 new
和 delete
。
Car * myArray = new Car[X];
此代码已创建 X
个汽车对象。您所要做的就是真正使用它们..
但是,我认为您的困惑在于:这是另一种方法
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 对象,这就是为什么您使用 new Car()
调用初始化每个 Car*
指针,这实际上创建了 Car 对象。
我同意您过多使用关键字 new
的评论。
我建议改用 std::vector
。
这是一个工作示例,其中 class Garage
在 heap/freestore 上有一个 Car
的向量,然后使用析构函数 [=15= 删除它]
示例仅供说明:
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();
}
上面使用new vector只是为了演示,不需要。为此,使用不带 new 的 std::vector
更快更安全,并且您无需在使用后删除它。
同时考虑使用智能指针而不是 new
。
您可以将对象添加到堆或栈中。如果将它添加到堆中,则可以随时动态创建它。这是使用 new 完成的,你会在 return.
中得到一个指针Car *aCar=new Car("BMW");
如果您在堆栈上创建它,您只需像定义其他变量一样定义它。
Car anotherCar("BMW");
如果在堆上创建,还需要从堆中释放。这是通过删除完成的。
delete aCar;
您永远不会释放在堆栈上创建的对象。当您超出范围时,它将自动解除分配。
至于创建数组,您可以创建静态或动态对象数组。
动态:
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;
您可以稳定地创建它们:
Car cars[]={"BWM", "AUDI"};
这次包括数组在内的所有对象都被压入栈中,当你超出范围时将被删除。
在这两者之间,您可以创建指向堆分配对象的基于堆栈的数组,或此处其他建议的堆分配静态数组。
至于 C++,我建议使用 std:: 库,在这种情况下 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));
我不确定我是怎么和一个两岁的孩子在一起的 post。 None 的答案确实给出了一个简单的 C++ 解决方案,所以这里是一个使用容器的 60 秒解决方案,看不到 new/delete。
#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";
}
}
不。 delete []myArray
只会导致称为 悬挂指针的东西.
这基本上意味着程序不再拥有指向的内存 myArray,但是 myArray 仍然指向那个内存。
为避免悬空指针,请在删除后将指针分配给 nullptr
。
delete[]myArray;
myArray = nullptr;