C++ 是一种“基于副本”的语言,例如,一个容器Entity
确实会将您提供给它的实体的副本放入容器中。
在许多地方都使用 C++ 制作了副本,因此最好您的班级正确支持它们或完全禁止它们。
您的类包含指向其他数据的指针:当您复制该类的实例时会发生什么?如果复制指针是可以的,那么显然不能在析构函数中删除指向的对象,因为仍然存在的副本将指向已删除的对象。
有一个简单的规则有助于避免这种错误,被称为“三法则”。如果您已明确编码
在您的班级中,您很可能需要所有三个。
在这种情况下,您有一个不是默认的析构函数(因为删除了指向的对象),因此您还需要告诉在复制构造或赋值的情况下要做什么。
如果您希望该类是不可复制的,那么只需确保
struct Entity {
Object *o;
Entity(Object *o) : o(o) {
...
}
~Entity() {
delete o;
}
private:
// Taboo... this should just never happen!!!
// Here is a declaration, but no implementation will be written
Entity(const Entity& other); // Copy constructor
Entity& operator=(const Entity&); // Assignment
};
声明禁止的操作private
将确保用户代码永远不会调用它们(这将是一个编译时错误),并且只声明它们而不提供实现将确保即使是类代码本身也不会错误地调用它们(你会得到链接时错误)。
但是,在这种特定情况下,这将禁止您的代码将Entity
实例放入容器中(必须复制容器内的元素)。您可以将Entity
指针放在容器中(指针可以被复制,因此std::vector<Entity *>
forentities
是合法的),但您将负责处理对象的正确生命周期(谁应该调用析构函数以及何时发生?)。
另一方面,如果您有一个指向类内部数据的指针,并且您希望允许复制该类的实例,您可以:
对于第二种解决方案,一种常见的方法是使用“引用计数”指针,即指向的数据“知道”有多少指针正在引用它,并且仅在该计数达到 0 时才被销毁。