删除指针向量时,调试断言失败

问题描述 投票:-1回答:3

我有一个vector持有pointer类:

vector<Entity*> editorElements;
vector<Entity*> entities;
vector<DirectionalLight*> dirLights;
vector<PointLight*> pointLights;
vector<SpotLight*> spotLights;

这段代码在我的班级Scene内。 Scene的ctor和析构函数是这样的:

Scene()
{
    editorElements = vector<Entity*>();
    entities = vector<Entity*>();
    dirLights = vector<DirectionalLight*>();
    pointLights = vector<PointLight*>();
    spotLights = vector<SpotLight*>();
}

~Scene()
{
    delete[] &entities;  // ERROR HERE
    delete[] &dirLights;
    delete[] &pointLights;
    delete[] &spotLights;
    delete[] &editorElements;
}

在析构函数中,我标记了一行ERROR HERE。我先放入哪个矢量并不重要,我总是得到错误。奇怪的是,它一直工作到最近(没有触及Scene类中的任何内容,或任何其他使用Scene实例的类)并且突然间它引发了异常:

enter image description here

如果vectors为空或有元素无关紧要,它会给出错误。

我需要帮助才能解决这个问题。

c++
3个回答
2
投票

因此描述了delete expression delete [] x

销毁由new [] - 表达式创建的数组

因此,如果delete[] &entities是由&entities表达式创建的数组,new[]才有意义。对?

entitiesstd::vector<Entity*>,而不是Entity[]。你没有用new[]创建它,所以你不能用delete[]删除它。

std::vector不是一个数组的语法糖,它是一个模板类,而std::vector<Entity*> entities不是一个数组,它是一个带有构造函数和析构函数的对象。那也告诉我们这句话

entities = vector<Entity*>();

什么都没有用 - entities是一个对象,所以它已经是默认构造的。你只是默认构建一个相同类型的匿名临时,并分配它。

最后,将原始指针存储在向量中是可以的,因为向量不负责对象的生命周期。在大多数情况下,最好让矢量拥有对象,这样您就不必担心手动删除它们,或者直接使用

vector<Entity>

或间接的

vector<unique_ptr<Entity>>

NB。一个好的准则是:你不应该在用户代码中使用newnew[]deletedelete[]

使用类对象来管理存储,因为编译器将负责为您调用其构造函数和析构函数。

如果您需要一个自定义类,请编写一个仅管理内存的类,以便与程序逻辑保持分离。否则,如果你真的需要所有权模型等,只需使用std::vectorstd::arraystd::unique_ptrstd::shared_ptr等标准库设施。


2
投票

向量不是新建的指针,更不用说新建的数组了。所以你不应该删除它们。如果你需要对存储在向量中的指针调用delete,你应该遍历向量,删除每个元素。但是你最好还是存储智能指针(例如std::unique_ptr<Entity>。那就是你需要存储指向动态分配对象的指针)。

请注意,如果最终删除析构函数中的元素,则还需要处理rule of three/five


1
投票

突然间它引发了异常

这是因为试图删除不应删除的内容。 The delete[] syntax用于删除动态分配的数组。但是你为它提供了一个指向std::vector实例的指针。因此编译器将此地址用于删除,就像它是一个数组一样,包括查找其大小然后删除整个段。但是没有这样的合适的数字,因为这不是一个数组,所以在运行时你最终会尝试删除你无权访问的地方的东西,因此你得到断言失败,因为这是一个访问违规,又称段错误。

此外,vector是一个管理自己记忆的类。如果你想释放这个容器中的实体 - 也就是动态分配的各个元素本身 - 那么你应该遍历它们并删除每个实体。方便地,例如,使用autorange-based for loop这样:

for (auto ptr : entities)
    delete ptr;

但是,在大多数情况下,您最好节省自己的内存管理开销,并选择std::unique_ptr而不是原始指针:

#include <memory>
...
std::vector<std::unique_ptr<Entity>> entities;

这样你就不必担心释放任何记忆,因为std:: unique_ptr一旦被破坏就会被释放,这是vector破坏的一部分。

此外,这是不必要的,可能不是您打算做的:

entities = vector<Entity*>();

因为vector对象本身已经在此行之前定义(因此它存在),并且它所做的只是创建一个相同的新对象并将其分配给entities

© www.soinside.com 2019 - 2024. All rights reserved.