C++11 为什么这里显式调用析构函数?

C++11 为什么这里显式调用析构函数?,c++11,c++-cli,destructor,C++11,C++ Cli,Destructor,在浏览一些与通过SMTP发送电子邮件相关的代码时,我在MSDN中得到了以下代码片段 static void CreateMessageWithAttachment( String^ server ) { String^ file = L"data.xls"; MailMessage^ message = gcnew MailMessage( L"jane@contoso.com",L"ben@contoso.com",L"Quarterly data report.",L"See

在浏览一些与通过SMTP发送电子邮件相关的代码时,我在MSDN中得到了以下代码片段

static void CreateMessageWithAttachment( String^ server )
{
   String^ file = L"data.xls";

   MailMessage^ message = gcnew MailMessage( L"jane@contoso.com",L"ben@contoso.com",L"Quarterly data report.",L"See the attached spreadsheet." );

   Attachment^ data = gcnew Attachment(file, MediaTypeNames::Application::Octet);

   ContentDisposition^ disposition = data->ContentDisposition;
   disposition->CreationDate = System::IO::File::GetCreationTime( file );
   disposition->ModificationDate = System::IO::File::GetLastWriteTime( file );
   disposition->ReadDate = System::IO::File::GetLastAccessTime( file );

   message->Attachments->Add( data );

   SmtpClient^ client = gcnew SmtpClient( server );

   client->Credentials = CredentialCache::DefaultNetworkCredentials;
   client->Send( message );

   data->~Attachment();
   client->~SmtpClient();
}
我只是想知道他们为什么在这里叫析构函数?我是不是遗漏了什么

 data->~Attachment();
 client->~SmtpClient();

在C++/CLI中,
ref
类析构函数是对

以下C++/CLI类在编译时:

public ref类测试
{
公众:
Test(){System::Console::WriteLine(“ctor”);}
~Test(){System::Console::WriteLine(“dtor”);}
静态void Foo()
{
auto foo=gcnew Test();
foo->~Test();
}
};
反编译到以下C#代码(C#语义更接近底层IL代码,因此这是可视化发生的情况的好方法):

公共类测试:IDisposable
{
公开考试()
{
控制台写入线(“ctor”);
}
私有void~Test()
{
控制台写入线(“dtor”);
}
公共静态void Foo()
{
新测试().Dispose();
}
受保护的虚拟void Dispose([Marshallas(UnmanagedType.U1)]bool A_0)
{
如果(A_0)
{
这个。~Test();
}
其他的
{
这个.Finalize();
}
}
公共虚拟void Dispose()
{
这个。处置(真实);
GC.SuppressFinalize((对象)this);
}
}
您可以看到dispose模式是由编译器自动实现的

~Test
“析构函数”被编译为私有方法,并为您生成
IDisposable::Dispose
的实现。出于某种原因,编译器还调用(空)终结器

另外,正如您在静态
Foo
方法中看到的,
Foo->~Test()
被简单地转换为调用
Dispose
。编译器不允许您调用
foo->Dispose()直接

但是调用“析构函数”(因此是
Dispose
方法)的标准方法是使用
delete
关键字:
delete foo
foo->~Test()相同foo
是托管句柄时,C++/CLI中的code>

请注意,在本例中,不要编写:

auto-foo=gcnew-CppCli::Test();
foo->Whatever();
删除foo;
您可以使用堆栈语义并编写:

testfoo;
foo.Whatever();
foo.~Test() FoO超出范围时,将调用代码>,如在常规C++中。

为了完整起见,下面是整个过程如何与终结器交互。让我们添加一个:

public ref类测试
{
公众:
Test(){System::Console::WriteLine(“ctor”);}
~Test(){System::Console::WriteLine(“dtor”);}
!Test(){System::Console::WriteLine(“终结器”);}
};
这将反编译为以下类似C的代码:

公共类测试:IDisposable
{
公开考试()
{
控制台写入线(“ctor”);
}
//这是真正的终结器
~Test()
{
本.处置(假);
}
//这就是C++/CLI编译~Test的目的
//让我们称之为方法A
私有void~Test()
{
控制台写入线(“dtor”);
}
//这是C++/CLI编译的!Test
//让我们称之为方法B
私有void!Test()
{
控制台写入线(“终结器”);
}
[HandleProcessCorruptedStateExceptions]
受保护的虚拟void Dispose([Marshallas(UnmanagedType.U1)]bool A_0)
{
如果(A_0)
{
这是.~Test();//MethodA,不是终结器
}
其他的
{
尝试
{
此。!Test();//方法B
}
最后
{
base.Finalize();
}
}
}
公共虚拟void Dispose()
{
这个。处置(真实);
GC.SuppressFinalize((对象)this);
}
}

请注意,为了增加混淆,在C#中,终结器是
~Test()
,它不同于C++/CLI编译器为析构函数生成的
private void~Test()
函数。

非常感谢您的详细解释,非常有用。您可能还应该注意到
~Test()
语法不是标准的。处理托管对象的规范方法是使用<代码>删除>代码>,与一个C++对象相同。@ DavidYaw OOP,你说得对,这是一个重要的点,谢谢!DavidYaw是的,这肯定不会那么令人困惑:)