C ++删除[]是否足以在数组后清理?

时间:2016-02-25 06:05:00

标签: 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") };

    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;
}

9 个答案:

答案 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;

不会删除为car1car2car3单独分配的对象。您也必须明确删除它们。

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;

看看这个讨论

delete[] an array of objects

答案 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_ptrunique_ptr等智能指针,而不是原始指针。这些可以让您在大多数情况下避免使用明确的newdelete

答案 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";
  }
}

live demo

答案 8 :(得分:0)

否。 delete []myArray只会导致称为悬挂指针的东西。

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

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

delete[]myArray;

myArray = nullptr;