简体   繁体   English

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

[英]C++ Is delete[] enough to clean up after an array?

In the code below I'm allocating an array dynamically by using the new keyword. 在下面的代码中,我通过使用new关键字动态分配数组。 Before I run out of scope I call delete[] on my array, and afterwards I set the punter to null. 在超出范围之前,我先对数组调用delete [] ,然后再将下标器设置为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. 我的问题是,如果足够,将delete []确保释放数组中所有3个Car对象的分配内存。 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. 在这里将名称设置为null是否足够。 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. 或者也许不需要将指针设置为null,因为它没有引用堆上的任何内容。

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

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. 在您的情况下,您已经从对new Car("BMW")调用中泄漏了内存,并且丢失了能够释放内存的指针。

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. 创建一个由3个Car对象组成的数组,然后为每个条目创建一个新的Car对象,使用它初始化数组中的对象,然后忽略新对象。

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. 在这种情况下,您的delete[]足以释放所使用的内存。

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. 调用Car析构函数后,没有人应该再次访问该对象的name (实际上这是未定义的行为),因此将其设置为null毫无意义。

Edit Note: As pointed out by R Sahu and Aslak Berby, Car * myArray = new Car[]{ ... }; 编辑说明:正如R Sahu和Aslak Berby所指出的, Car * myArray = new Car[]{ ... }; is not a valid way to make an array, use Car * myArray = new Car[3]{ ... }; 不是创建数组的有效方法,请使用Car * myArray = new Car[3]{ ... }; instead. 代替。

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 . 不会删除分别为car1car2car3分配的对象。 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. 由于Car没有默认的构造函数。 You can add a default constructor to Car . 您可以向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. 释放内存。

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 是的,仅当您创建Car元素的普通数组时, Car足够,因为数组名称是指向其第一个元素的指针

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 看看这个讨论

delete[] an array of objects delete []对象数组

Car * myArray = new Car[X];

This code already creates X Car objects. 此代码已创建X Car对象。 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. 此代码分配3个Car*指针的数组。 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. 因此,您尚未创建任何Car对象,这就是为什么要使用一个new Car()调用来初始化每个Car*指针的原因,该调用实际上创建了Car对象。

Basically you need a delete (or delete[] ) for every new . 基本上,您需要为每个new delete (或delete[] )。 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 . 代替原始指针,您应该学习使用诸如shared_ptrunique_ptr类的智能指针。 These let you avoid explicit new and delete in most cases. 这些使您在大多数情况下避免显式的newdelete

I agree with the comments that you are using the keyword new too much. 我同意您过多使用关键字new的评论。

I suggest using std::vector instead. 我建议改用std::vector

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 这里是一个工作示例,其中类Garage拥有的矢量Car的对堆/的FreeStore后来与析构函数删除它~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. 为此,使用没有新的std::vector更快,更安全,并且在使用后无需删除它。

Also consider using Smart Pointers instead of using new . 还可以考虑使用智能指针,而不要使用new

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. 这是使用new完成的,您将获得一个指针作为回报。

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. 至于创建数组,您可以创建statick或dynamicall对象的数组。

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; 至于C ++,我建议使用std ::库,在这种情况下,建议使用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));

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. 没有一个答案能真正提供一个简单的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 现场演示

No. delete []myArray Will merely result in something called a dangling pointer . delete []myArray仅会导致称为“ 悬空指针”的情况

Which basically means that the program no longer owns the memory pointed to myArray , but myArray still points to that memory. 这基本上意味着程序不再拥有指向myArray的内存,但是myArray仍然指向该内存。

To avoid dangling pointers assign your pointer to nullptr after deletion. 为避免指针悬空,删除后将指针分配给nullptr

delete[]myArray;

myArray = nullptr;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM