繁体   English   中英

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

[英]Debug assertion failed when deleting a vector of pointers

我有一个保存pointer类的pointervector

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实例的任何其他类中的任何东西),它都运行良好,突然之间它引发了一个异常:

在此处输入图片说明

vector s为空或有元素都没有关系,它给出的误差都相同。

我需要协助以解决此问题。

向量不是更新的指针,更不用说更新的数组了。 因此,您不应该删除它们。 如果需要对向量中存储的指针调用delete,则应遍历向量,删除每个元素。 但是最好改为存储智能指针(例如std::unique_ptr<Entity> 。也就是说,如果您需要存储所有指向动态分配对象的指针。

请注意,如果最终删除了析构函数中的元素,则还需要注意3/5的规则

删除表达式 delete [] x的描述如下:

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

因此delete[] &entities &entities是由new[] -expression创建的数组时, delete[] &entities 才有意义。 对?

但是entitiesstd::vector<Entity*> ,而不是Entity[] 您不是使用new[]创建它的,因此不能使用delete[]删除它。

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

entities = vector<Entity*>();

没有任何用处- entities是一个对象,因此它已经是默认构造的。 您只是默认构造一个相同类型的匿名临时文件,然后进行分配。

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

vector<Entity>

或间接与

vector<unique_ptr<Entity>>

注意 一个好的原则是:你不应该使用newnew[] deletedelete[]在用户代码在所有

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

如果需要自定义类,请编写一个管理内存的类,以免与程序逻辑脱钩。 否则,如果您确实需要该所有权模型,则只需使用标准库工具,例如std::vectorstd::arraystd::unique_ptrstd::shared_ptr等等。

突然间它提出了一个例外

这是因为尝试删除不应该删除的内容。 delete[]语法用于删除动态分配的数组 但是您为它提供了一个指向std::vector实例的指针。 因此,编译器将此地址当作删除对象,就好像它是一个数组一样,其中包括找出其大小,然后删除整个段。 但是没有合适的数字,因为它不是数组,所以在运行时,您最终试图在没有访问权限的地方删除某些内容,因此断言失败,因为这是访问违反,也称为段错误。

同样, vector是管理自己的内存的类。 如果要释放保存在此容器中的实体(即,动态分配的各个元素本身),则应遍历它们并删除每个元素。 例如,方便地使用auto和基于范围的for循环,如下所示:

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

暂无
暂无

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

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