析构函数调用和指针
Destructor call and pointers
这是我的问题假设我有一个函数,它由这样的东西组成:
void function() {
entity e; //entity is just a class
entities.push_back(e); //entities is a vector of entity objects
}
这就是困扰我的事情。"e"包含指向另一个对象的指针。调用实体的析构函数时,它会删除该指针。由于"e"和实体中的实体都指向同一位置,如果我从实体(在函数外部)对该指针执行某些操作,它会给出错误,因为一旦函数返回,指针上的任何内容都会被删除。解决此问题的最佳方法是什么?
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
指针放在容器中(可以复制指针,以便entities
std::vector<Entity *>
是合法的),但您将负责处理对象的正确生存期(谁应该调用析构函数以及何时发生?
另一方面,如果你有一个指向类内部数据的指针,并且你想要允许创建类实例的副本,你可以:
- 同时复制指向的数据
- 在不同实例之间共享指向数据
对于第二种解决方案,一种常见的方法是使用"引用计数"指针,即指向的数据"知道"有多少指针引用它,并且仅当该计数达到 0 时才被销毁。
更改指向共享对象的指针以包含shared_ptr
将是一个简单的解决方案。
这是因为你违反了三法则:如果你有一个析构函数,你几乎肯定也需要有一个复制构造函数和一个赋值运算符。
当然,处理指针的最好方法是找到一种完全没有指针的方法("零规则"):在这种情况下,编译器生成的析构函数、构造函数和赋值运算符会负责自动为您管理资源。
如果实体类具有析构函数,则还应按三规则定义复制和复制赋值运算符。
不幸的是,这可能意味着您必须复制对象中指向的项目,以便在销毁对象的副本时不会删除稍后将被其他副本删除的项目。 "不幸的是",因为创建指向项的副本通常是不可取的;在这种情况下,你有一个设计难题 - 尽管Tom Kerr的建议WRT shared_ptr
是一个不错的选择。
另一种解决方案是禁止复制,方法是将复制构造函数设为私有,或者 (C++11) 通过使用 = delete
,并entity
一个指针数组代替(和 push_back(&e)
)。
- 使用共享指针的函数调用,其对象应为 const
- 返回指向对象的指针的函数调用是否为 prvalue?
- VkSurfaceKHR 指针的值在函数调用后更改,无需任何显式赋值
- 指针在函数调用后更改其地址
- C++:这是使用整数变量作为函数调用指针的正确方法吗
- 使用函数指针时,ESP 未在函数调用中正确保存
- 为什么分配了 nullptr 的指针可以调用成员函数?
- 函数调用歧义(用户定义的转换和 Derived2Base 指针转换)
- 创建指针时是否没有构造函数调用
- 在父指针上调用虚函数
- 如何从另一个类调用指向成员的指针函数
- 在数组函数指针中调用void
- 这些函数调用的返回指针的区别是什么?
- 为什么我不能在插入的函数调用中直接使用返回的指针作为参数
- C++ 通过函数指针错误调用成员函数
- 函数调用中的 void 指针在 C++ 与 C 中
- 析构函数在与 STL 的共享指针中调用两次
- C++ 指针 - 函数调用中的重新分配
- C++递归指针函数调用
- 如何编写一个可以处理对象或指针函数调用的模板函数