是否可以在其析构函数中使用指向已销毁对象的指针?
Can I use a pointer to a destructed object inside its destructor?
我是否可以从其析构函数内的指针访问已销毁的对象?是否保证对象仍位于该指针位置并可访问? 例如,在下面的代码中,我销毁了 a1,并在其析构函数中从指向 a1 的 a2 访问 a1。
#include <iostream>
class A
{
public:
A(int* i) : m_i(i) {}
~A();
int* m_i;
};
A* a1;
A* a2;
int x = 0;
A::~A()
{
*a2->m_i = 1;
}
int main()
{
a1 = new A(&x);
a2 = a1;
delete a1;
std::cout << x << std::endl;
return 0;
}
这是一个很好的问题。基本答案是,当A
对象的析构函数启动时,对象的生存期结束,但在A
的析构函数完成之前,访问A
对象的成员(有一些限制(仍然是合法的。标准参考是:
[basic.life]/1:
。类型为
T
o
的对象生存期在以下时间结束:如果T
是具有非平凡析构函数 (15.4( 的类类型,则析构函数调用开始,...
[basic.life]/6:
在对象的生存期开始之前,但在对象将占用的存储之后 已分配41,或者在对象的生存期结束之后,在该对象占用的存储之前 重用或释放,表示对象将所在的存储位置地址的任何指针,或 可以以有限的方式使用。关于正在建造或销毁的物体,见15.7。...
[class.cdtor]/2 (即15.7/2(:
。为了形成指向对象
obj
的直接非静态成员的指针(或访问其值(,obj
的构造应该已经开始,并且它的销毁不应该完成,否则指针值的计算(或访问 成员值(会导致未定义的行为。
因此,由于对a2->m_i
的访问发生在对象*a2
析构函数的执行时,因此是允许的。(注意:A::m_i
是A
的直接成员,因为A
没有基类。
请注意,(正如其他人已经指出的那样(,在析构函数完成之前,不会释放存储A
对象的内存。这就是delete
表达式的工作方式。
a1
指向的对象在析构函数退出之前不会被销毁。 这意味着可以在析构函数中调用任何成员函数以及访问和成员变量。
你的代码,按原样,是有效的。
与delete a1;
一起使用的delete
运算符执行以下操作:
- 它使用其静态类型破坏
a1
指向的对象,即执行a1.~A()
- 它使用
::operator delete(a1)
来释放a1
指向的对象曾经所在的内存(假设您没有重载它......
第一步中调用的析构函数依次执行以下两个操作:
- 执行用户定义的代码。
- 销毁所有成员对象(通过使用其析构函数(。
总之,首先执行您的代码(此时 a1 和 a2 都有效,并且对象仍然存在(,然后销毁成员(现在该操作在技术上是无效的,但仍然像通常具有相当无聊析构函数的int
一样工作(,最后释放内存(之后执行该操作将非常糟糕(。
如果表达式不是空指针,并且释放函数不是销毁删除(自 C++20 起(,则删除表达式将为要销毁的对象或要销毁的数组的每个元素(从数组的最后一个元素到第一个元素(调用析构函数(如果有(。
之后,无论任何析构函数是否抛出异常,delete 表达式都会调用释放函数:运算符 delete(对于表达式的第一个版本(或运算符 delete[](对于表达式的第二个版本(
https://en.cppreference.com/w/cpp/language/delete
因此,析构函数将在释放之前被调用。
- 对象指针在c++中是如何工作的
- C++ 对象指针数组的复制构造函数
- 在对象指针上调用 Delete 是否会递归删除其动态分配的成员
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 正确初始化和销毁对象指针的C++数组?
- 如何深度复制链表对象指针
- 对象指针 c++ 的全局向量错误
- 如何将 c++ 类包装到 python 中,以便我可以使用 pybind11 访问其成员的公共方法(成员是一个对象指针)
- 静态对象指针
- 正在将对象指针数组初始化为NULL
- 如何使用条件表达式返回对象指针?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- 使用C对象指针构建PyObject*
- 如何在使用对象指针时访问成员函数
- 静态强制转换允许转换对象指针,但不允许转换整数
- C++ abort() 在函数内的抽象类对象指针调用上
- 指向函数的对象指针
- 访问指向对象指针向量的指针的第一个元素?
- 如何将对象/指针正确存储到 Qlist 中
- 对象指针打印结果以相反的顺序进行