我有一个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
实例的类)并且突然间它引发了异常:
如果vector
s为空或有元素无关紧要,它会给出错误。
我需要帮助才能解决这个问题。
因此描述了delete expression delete [] x
:
销毁由new [] - 表达式创建的数组
因此,如果delete[] &entities
是由&entities
表达式创建的数组,new[]
才有意义。对?
但entities
是std::vector<Entity*>
,而不是Entity[]
。你没有用new[]
创建它,所以你不能用delete[]
删除它。
std::vector
不是一个数组的语法糖,它是一个模板类,而std::vector<Entity*> entities
不是一个数组,它是一个带有构造函数和析构函数的对象。那也告诉我们这句话
entities = vector<Entity*>();
什么都没有用 - entities
是一个对象,所以它已经是默认构造的。你只是默认构建一个相同类型的匿名临时,并分配它。
最后,将原始指针存储在向量中是可以的,因为向量不负责对象的生命周期。在大多数情况下,最好让矢量拥有对象,这样您就不必担心手动删除它们,或者直接使用
vector<Entity>
或间接的
vector<unique_ptr<Entity>>
NB。一个好的准则是:你不应该在用户代码中使用new
,new[]
,delete
或delete[]
。
使用类对象来管理存储,因为编译器将负责为您调用其构造函数和析构函数。
如果您需要一个自定义类,请编写一个仅管理内存的类,以便与程序逻辑保持分离。否则,如果你真的需要所有权模型等,只需使用std::vector
,std::array
,std::unique_ptr
,std::shared_ptr
等标准库设施。
向量不是新建的指针,更不用说新建的数组了。所以你不应该删除它们。如果你需要对存储在向量中的指针调用delete,你应该遍历向量,删除每个元素。但是你最好还是存储智能指针(例如std::unique_ptr<Entity>
。那就是你需要存储指向动态分配对象的指针)。
请注意,如果最终删除析构函数中的元素,则还需要处理rule of three/five。
突然间它引发了异常
这是因为试图删除不应删除的内容。 The delete[]
syntax用于删除动态分配的数组。但是你为它提供了一个指向std::vector
实例的指针。因此编译器将此地址用于删除,就像它是一个数组一样,包括查找其大小然后删除整个段。但是没有这样的合适的数字,因为这不是一个数组,所以在运行时你最终会尝试删除你无权访问的地方的东西,因此你得到断言失败,因为这是一个访问违规,又称段错误。
此外,vector
是一个管理自己记忆的类。如果你想释放这个容器中的实体 - 也就是动态分配的各个元素本身 - 那么你应该遍历它们并删除每个实体。方便地,例如,使用auto
和range-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
。