为什么在这里明确地调用destruct?

时间:2017-02-16 22:46:15

标签: 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 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();

1 个答案:

答案 0 :(得分:2)

在C ++ / CLI中,ref类析构函数是Dispose pattern的抽象。

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

public ref class Test
{
public:
    Test() { System::Console::WriteLine("ctor"); }
    ~Test() { System::Console::WriteLine("dtor"); }

    static void Foo()
    {
        auto foo = gcnew Test();
        foo->~Test();
    }
};

反编译为以下C#代码(C#语义更接近底层IL代码,因此它是一种可视化发生情况的好方法):

public class Test : IDisposable
{
    public Test()
    {
        Console.WriteLine("ctor");
    }

    private void ~Test()
    {
        Console.WriteLine("dtor");
    }

    public static void Foo()
    {
        new Test().Dispose();
    }

    protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool A_0)
    {
        if (A_0)
        {
            this.~Test();
        }
        else
        {
            this.Finalize();
        }
    }

    public virtual void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize((object)this);
    }
}

您可以看到配置模式是由编译器自动实现的。

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

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

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

请注意,在此示例中,而不是写:

auto foo = gcnew CppCli::Test();
foo->Whatever();
delete foo;

你可以使用堆栈语义并写:

Test foo;
foo.Whatever();
foo.~Test();超出范围时,将调用

foo,就像常规C ++一样。

为了完整性,这里是整个事物与终结者的交互方式。我们加一个:

public ref class Test
{
public:
    Test() { System::Console::WriteLine("ctor"); }
    ~Test() { System::Console::WriteLine("dtor"); }
    !Test() { System::Console::WriteLine("finalizer"); }
};

这反编译为以下类似C#的代码:

public class Test : IDisposable
{
    public Test()
    {
        Console.WriteLine("ctor");
    }

    // This is the real finalizer
    ~Test()
    {
        this.Dispose(false);
    }

    // This is what C++/CLI compiles ~Test to
    // Let's call this MethodA
    private void ~Test()
    {
        Console.WriteLine("dtor");
    }

    // This is what C++/CLI compiles !Test to
    // Let's call this MethodB
    private void !Test()
    {
        Console.WriteLine("finalizer");
    }

    [HandleProcessCorruptedStateExceptions]
    protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool A_0)
    {
        if (A_0)
        {
            this.~Test(); // MethodA, NOT the finalizer
        }
        else
        {
            try
            {
                this.!Test(); // MethodB
            }
            finally
            {
                base.Finalize();
            }
        }
    }

    public virtual void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize((object)this);
    }
}

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