免责声明:我知道这是不好的设计,我只是出于好奇问问题,以便更深入地了解C++中析构函数的工作原理。
在C#中,可以在类的析构函数中编写GC.KeepAlive(this)
(请参见下面的编辑),这意味着即使析构函数调用完成后,对象仍将存活在内存中。
C++的设计是否允许从析构函数中复活对象,类似于上述C#算法?
编辑:正如下面的答案所指出的那样,GC.ReRegisterForFinalize()
与问题更相关,而不是GC.KeepAlive(this)
。
免责声明:我知道这是不好的设计,我只是出于好奇问问题,以便更深入地了解C++中析构函数的工作原理。
在C#中,可以在类的析构函数中编写GC.KeepAlive(this)
(请参见下面的编辑),这意味着即使析构函数调用完成后,对象仍将存活在内存中。
C++的设计是否允许从析构函数中复活对象,类似于上述C#算法?
编辑:正如下面的答案所指出的那样,GC.ReRegisterForFinalize()
与问题更相关,而不是GC.KeepAlive(this)
。
finalize()
这个东西,可以在对象的生命周期中添加一个波浪线,但不能改变可达性原则。显然,其他具有垃圾回收功能的语言不需要具有这样的功能,因此支持生命周期扩展与是否具有 gc 无关。 - HolgerGC.KeepAlive
的作用。它不是用于在对象析构函数中保留对象不被销毁的--实际上,GC.KeepAlive()
为空,没有实现。
可以在这里查看.NET源代码。
它确保在调用GC.KeepAlive
之前,传递的对象参数不会被垃圾回收器回收。传递给KeepAlive的对象参数可以在调用GC.KeepAlive
后立即被垃圾回收。由于KeepAlive
没有实际实现,这纯粹基于编译器必须维护对要传递为KeepAlive
参数的对象的引用。任何其他函数(不被编译器或运行时内联)都可以使用该对象作为参数。KeepAlive
的注释中的这句话:“[...]这可能会对终结器线程造成微妙的----。”。破折号是什么意思,是为了“FU”的审查吗?开发人员在文档中不能提到“bug”这个词吗?是什么原因? - CompuChipGC.KeepAlive
能够工作的唯一原因是因为 JIT 对它进行了特殊处理,否则在内联函数之后,JIT 将会发现它不需要保持该引用。 - Voo这里有一个想法:
C* gPhoenix= nullptr;
C::~C ()
{
gPhoenix= new C (*this); // note: loses any further-derived class ("slice")
}
如果涉及的对象(基类或成员)确实有执行操作的析构函数,并且您使用delete gPhoenix;
,那么就会遇到问题,因此您需要更复杂的机制,具体取决于它真正想要实现的内容。但是,如果您没有任何实际目标,只是好奇地探索,那么指出这一点就足够了。
当析构函数的主体被调用时,对象仍然完好无损。您从析构函数内部进行正常的成员函数调用时,它看起来非常重要和正常。
拥有对象的内存将被回收,因此您不能留在原地。并且在离开主体后,其他销毁会自动发生,无法干扰。但是,在此之前,您可以复制对象。
正如已经指出的那样,GC.KeepAlive
并不能做到这一点。
只要涉及到.NET,使用GC.ReRegisterForFinalize
可以从终结器中复活,如果有WeakReference
或GCHandle
跟踪复活,或者将this
传递给类外部的某个东西,仍然可以获取对它的引用。这样做将中止销毁过程。
GC.ReRegisterForFinalize
来接近您在.NET中描述的行为。
在C++中,您已经得到了正确的答案。
任何语言都不可能做到这一点。
您的理解有些偏差。 GC.KeepAlive
将标记对象为垃圾回收器无法回收的对象。如果对象在非托管代码中使用,垃圾回收器无法跟踪其使用情况,则会防止垃圾回收策略销毁对象。这并不意味着对象在销毁后仍然在内存中。
一旦对象开始销毁,代码将释放资源(内存、文件处理程序、网络连接)。通常的顺序是从最深层的派生类返回到基类。如果中间某个部分阻止了销毁,就不能保证可以重新获取这些资源,并且对象会处于不一致状态。
您更希望拥有一个 std::shared_ptr
,它跟踪副本和引用,并且只有在没有人再需要它时才销毁对象。
GC.KeepAlive
的理解是错误的。此外,在非托管代码中使用对象时需要将其固定,这时它就无法被垃圾回收了。 - Lucas Trzesniewski#include <iostream>
#include <iomanip>
namespace test
{
class GotNormalDestructor
{
public:
~GotNormalDestructor() { std::wcout << L"~GotNormalDestructor(). this=0x" << std::hex << this << L"\n"; }
};
class GotVirtualDestructor
{
public:
virtual ~GotVirtualDestructor() { std::wcout << L"~GotVirtualDestructor(). this=0x" << std::hex << this << L"\n"; }
};
template <typename T>
static void create_destruct_delete(wchar_t const name[])
{
std::wcout << L"create_destruct_delete<" << name << L">()\n";
{
T t;
std::wcout << L"Destructing auto " << name << L" explicitly.\n";
t.~T();
std::wcout << L"Finished destructing " << name << L" explicitly.\n";
std::wcout << name << L" going out of scope.\n";
}
std::wcout << L"Finished " << name << L" going out of scope.\n";
std::wcout << L"\n";
}
template <typename T>
static void new_destruct_delete(wchar_t const name[])
{
std::wcout << L"new_destruct_delete<" << name << L">()\n";
T *t = new T;
std::wcout << L"Destructing new " << name << L" explicitly.\n";
t->~T();
std::wcout << L"Finished destructing new " << name << L" explicitly.\n";
std::wcout << L"Deleting " << name << L".\n";
delete t;
std::wcout << L"Finished deleting " << name << L".\n";
std::wcout << L"\n";
}
static void test_destructor()
{
{
std::wcout << L"\n===auto normal destructor variable===\n";
GotNormalDestructor got_normal;
}
{
std::wcout << L"\n===auto virtual destructor variable===\n";
GotVirtualDestructor got_virtual;
}
{
std::wcout << L"\n===new variables===\n";
new_destruct_delete<GotNormalDestructor>(L"GotNormalDestructor");
new_destruct_delete<GotVirtualDestructor>(L"GotVirtualDestructor");
}
{
std::wcout << L"\n===auto variables===\n";
create_destruct_delete<GotNormalDestructor>(L"GotNormalDestructor");
create_destruct_delete<GotVirtualDestructor>(L"GotVirtualDestructor");
}
std::wcout << std::endl;
}
}
int main(int argc, char *argv[])
{
test::test_destructor();
return 0;
}
示例输出
===auto normal destructor variable===
~GotNormalDestructor(). this=0x0x23fe1f
===auto virtual destructor variable===
~GotVirtualDestructor(). this=0x0x23fe10
===new variables===
new_destruct_delete<GotNormalDestructor>()
Destructing new GotNormalDestructor explicitly.
~GotNormalDestructor(). this=0x0x526700
Finished destructing new GotNormalDestructor explicitly.
Deleting GotNormalDestructor.
~GotNormalDestructor(). this=0x0x526700
Finished deleting GotNormalDestructor.
new_destruct_delete<GotVirtualDestructor>()
Destructing new GotVirtualDestructor explicitly.
~GotVirtualDestructor(). this=0x0x526700
Finished destructing new GotVirtualDestructor explicitly.
Deleting GotVirtualDestructor.
~GotVirtualDestructor(). this=0x0x526700
Finished deleting GotVirtualDestructor.
===auto variables===
create_destruct_delete<GotNormalDestructor>()
Destructing auto GotNormalDestructor explicitly.
~GotNormalDestructor(). this=0x0x23fdcf
Finished destructing GotNormalDestructor explicitly.
GotNormalDestructor going out of scope.
~GotNormalDestructor(). this=0x0x23fdcf
Finished GotNormalDestructor going out of scope.
create_destruct_delete<GotVirtualDestructor>()
Destructing auto GotVirtualDestructor explicitly.
~GotVirtualDestructor(). this=0x0x23fdc0
Finished destructing GotVirtualDestructor explicitly.
GotVirtualDestructor going out of scope.
~GotVirtualDestructor(). this=0x0x23fdc0
Finished GotVirtualDestructor going out of scope.