[英]Debug assertion failed when deleting a vector of pointers
我有一个保存pointer
类的pointer
的vector
:
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
才有意义。 对?
但是entities
是std::vector<Entity*>
,而不是Entity[]
。 您不是使用new[]
创建它的,因此不能使用delete[]
删除它。
std::vector
不是数组的语法糖,它是模板类,而std::vector<Entity*> entities
不是数组,它是具有构造函数和析构函数的对象。 这也告诉我们,这句话
entities = vector<Entity*>();
没有任何用处- entities
是一个对象,因此它已经是默认构造的。 您只是默认构造一个相同类型的匿名临时文件,然后进行分配。
最后,在这里将原始指针存储在向量中是可以的,因为向量不影响对象的生存期。 在大多数情况下,最好让向量拥有对象,这样您就不必担心手动删除它们,直接使用
vector<Entity>
或间接与
vector<unique_ptr<Entity>>
注意 一个好的原则是:你不应该使用new
, new[]
delete
或delete[]
在用户代码在所有 。
使用类对象来管理您的存储,因为编译器将为您调用其构造函数和析构函数。
如果需要自定义类,请编写一个仅管理内存的类,以免与程序逻辑脱钩。 否则,如果您确实需要该所有权模型,则只需使用标准库工具,例如std::vector
, std::array
, std::unique_ptr
, std::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.