2

我的一位同事在周末看到了一篇关于 codeproject 的文章,其中描述了auto_handle 方法的使用。鉴于这篇文章是在 2006 年写的,这仍然是处理文件句柄等确定性处置的正确方法吗?

我们倾向于显式地刷新和关闭文件句柄,然后删除指针并将它们清空,以确保 GC 没有理由不收集它们(是的,我们知道我们是超级偏执的)。使用类似 auto_handle 的东西看起来可以帮助我们变得更加懒惰(我们喜欢在安全的情况下变得懒惰)但是我们不想开始使用它现在被认为是不好的做法和/或我们可以使用更好的东西.

4

3 回答 3

4

自 2005 年发布以来,C++/CLI 没有改变,因此没有理由假设发生了任何新情况。与 2005 年有效的建议相同,auto_handle并不是自动删除对象的最佳方式。您应该首先考虑堆栈语义,它涵盖了绝大多数情况。编译器自动生成 try/finally 块和delete调用(即释放对象),相当于 C# using语句,减去代码。链接中给出的示例是这样完成的:

void Demo1A()
{
    StreamWriter sw("c:\\temp\\test.txt");
    sw.WriteLine("This is a line of text");
}   // <=== Compiler auto-generates the StreamWriter::Dispose call here

请注意对象声明中缺少的 ^ 帽子。

并且考虑这与垃圾收集器无关,仅与确定性资源清理有关。另请注意,将局部变量设置为 nullptr 是非常不合适的,它可以不必要地延长引用的生命周期超出其实际使用。抖动优化器删除分配。

于 2012-06-18T17:05:15.790 回答
2

是的,它仍然是处理确定性处置的正确方法。使用 auto_handle 是 C# using 语句的 C++/CLI 等效项。

使用 auto_handle(它使用 RAII)可以让您获得异常安全性(即,即使抛出异常,对象也会被释放),而无需编写任何 try-catch。

另请参阅:C++/CLI 资源管理混乱

于 2012-06-18T14:28:55.330 回答
0

我认为,有一种更简单的方法可以对托管对象进行确定性处理。只需在没有 a 的情况下声明它们^,您将获得与*不使用非托管 C++ 类相同类型的行为:初始化变量时调用构造函数,而“析构函数”(实际上是 Dispose 方法)当变量超出范围时调用。

当它被编译时,如果它是一个局部变量,它会变成一个 try-catch-dispose,或者如果它是一个类字段,它会在该类的 Dispose 方法中添加一行。

这与 auto_handle 没有太大区别,auto_handle 在其析构函数中调用了 Dispose,但我认为语法更易于使用。

例子:

C++/CLI:

public ref class Foo
{
    AutoResetEvent are;

public:
    Foo() : are(false)
    {
        this->are.Set(); // Use a '.' to access members.
    }

    void SomeMethod()
    {
        AutoResetEvent are2(false);
        are2.Set();
    }
};

等效的 C#,来自 Reflector,所以你可以看到它在幕后做了什么:

public class Foo : IDisposable
{
    // Fields
    private readonly AutoResetEvent modreq(IsByValue) are;

    // Methods
    public Foo()
    {
        AutoResetEvent modopt(IsConst) event2 = new AutoResetEvent(false);
        try
        {
            this.are = event2;
            base..ctor();
            this.are.Set();
        }
        fault
        {
            this.are.Dispose();
        }
    }

    public void ~Foo()
    {
    }

    public sealed override void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    [HandleProcessCorruptedStateExceptions]
    protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1)
    {
        if (flag1)
        {
            try
            {
                this.~Foo();
            }
            finally
            {
                this.are.Dispose();
            }
        }
        else
        {
            base.Finalize();
        }
    }

    public void SomeMethod()
    {
        AutoResetEvent are2 = null;
        AutoResetEvent modopt(IsConst) event2 = new AutoResetEvent(false);
        try
        {
            are2 = event2;
            are2.Set();
        }
        fault
        {
            are2.Dispose();
        }
        are2.Dispose();
    }
}
于 2012-06-18T16:17:45.890 回答