C++是删除[]足够清理数组之后?

C++是删除[]足够清理数组之后?,c++,arrays,pointers,dynamic-memory-allocation,C++,Arrays,Pointers,Dynamic Memory Allocation,在下面的代码中,我使用new关键字动态分配数组。在超出作用域之前,我在数组上调用delete[],然后将punter设置为null 我的问题是,如果这足够的话,将删除[]以确保为数组中的所有3个Car对象分配的内存都已释放。还是我必须做一些特定的事情来释放每个对象使用的内存 void main() { Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") }; delet

在下面的代码中,我使用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是一个字符指针。或者,可能不需要将指针设置为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;
}

在您的情况下,您已经从对new CarBMW的调用中泄漏了内存,并且丢失了能够释放内存的指针

这一行:

Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
创建一个包含3个汽车对象的数组,然后为每个条目创建一个新的汽车对象,使用它初始化数组中的对象,然后忘记新对象

可以更简单地这样写:

Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
甚至

Car * myArray = new Car[3]{ "BMW", "AUDI", "SKODA" };
在这种情况下,您的delete[]足以释放所使用的内存

注意

Car::~Car()
{
    name = nullptr;
}
不做任何事情来释放内存。一旦调用了汽车析构函数,任何人都不应该再次访问该对象的名称——事实上,它是未定义的行为,所以将其设置为null没有什么意义


编辑注:正如R Sahu和Aslak Berby所指出的,Car*myArray=newcar[]{…};不是生成数组的有效方法,请使用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;
看看这个讨论

您不能使用:

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;
取消分配内存。

基本上,对于每个新的内存,您需要一个delete或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对象,这就是为什么您使用新的Car调用初始化每个Car*指针,这实际上创建了Car对象。

我同意您使用关键字new太多的评论

我建议改用std::vector

下面是一个工作示例,其中类Garage在heap/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可以更快、更安全地实现这一目的,并且在使用后不需要删除它


也可以考虑使用智能指针,而不是使用NeX.

。可以将对象添加到堆或堆栈中。如果您将其添加到堆中,则可以动态创建它。这是使用new完成的,您将得到一个指针作为回报

Car *aCar=new Car("BMW");
如果在堆栈上创建它,则只需像使用其他变量一样定义它

Car anotherCar("BMW");
如果在堆上创建它,还需要从堆中取消分配它。这是用delete完成的

delete aCar;
您从未解除分配在堆栈上创建的对象。当您超出范围时,它将自动解除分配

至于创建数组,您可以创建statick或DynamicCall对象的数组

动态:

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"};
这一次,包括数组在内的所有对象都被推送到堆栈中,并且在超出范围时将被删除

在这两者之间,您可以创建一个基于堆栈的数组,指向堆分配的对象,或者一个heaplocated静态数组,正如这里的其他建议一样

<> P>关于C++,我建议使用STD::库,在这种情况下,STD::向量; 要么:

std::vector<Car *> myArray;
myArray.push_back(new Car("BMW"));

.....
// Cleanup:
for(auto car : myArray)
     delete car;
或:


我不知道我怎么会在这里工作了两年。没有一个答案能给出一个简单的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";
  }
}
否。删除[]myArray只会导致一个称为悬空指针的东西

这基本上意味着程序不再拥有指向的内存 myArray,但myArray仍然指向该内存

为了避免指针悬空,删除后将指针分配给nullptr

删除[]myArray


myArray=nullptr

你用新方法太多了。几乎没有理由去做新的事情。不要。说真的,别这样。现在,忘了你曾经听说过新的。你不需要它,也不想要它。新表达式的数组形式尤其糟糕,即使在将来确实需要使用new的情况下,也不应该使用new数组。如果需要动态数组,请使用std::vector。如果您不太可能需要动态指针数组,请查找Boost和/或使用向量。哦,main返回一个int。你使用的指针太多了。下面是一个例子,在堆/空闲存储上创建一个向量,然后使用析构函数将其删除:在指针超出范围之前将其设置为null没有任何用处。Car*myArray=new Car[3];这不会在第一时间编译,因为OP没有为Carthat定义默认构造函数,因为OP应该做一些不同的事情。添加了更多的代码来澄清我的答案,效果更好。剩下的唯一问题是数组不是指针,但这太离题了,在这里无关紧要。关于这个主题的阅读很好:左边是数组不是指针,我最好不要试图解释你在这里要说的。工作得更好我从来没有改进过任何代码让它工作得更好。这是我写的唯一一个片段,当然它是有效的。new std::vector是如此错误,请不要这样做。你正朝着正确的方向迈出一步,所以请保持std::vector。然后你甚至不需要定义析构函数。@stefan是的,你是对的,但它只用于演示特别是作为初学者的演示,在示例代码附近没有新代码是很有价值的-Car*myArray=new Car[]{*new Car..充其量是指向指针数组的指针。这意味着Car*myArray首先是错误的。此外,我认为您不能以这种方式静态分配具有动态创建内容的对象数组。您必须先创建数组,然后创建元素。Car**myArray=new Car**[3];myArray[0]=new CarBMW;…@AslakBerby:这毫无意义。Car*myArray是指向一辆或多辆车的指针,而不是指向指针的指针。new Car[]创建一个车数组,而不是指针数组。而*new CarBMW是一个车对象,不是指针。这也是内存泄漏,但这与此无关。@mAlter构造new Car[n]创建一个Car数组。new Car[]={new Car}是非法的,但在我的头脑中是指向指针的指针。正确的语法应该是Car*myArray[]={new CarBMW,…};@AslakBerby:都是真的,但你的第一个评论是关于一个不同的形式,它实际上不是指向指针数组的指针。@MSalters:我看到我解释得很糟糕。
#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";
  }
}