避免早期完成拥有本机资源的ref类

时间:2018-02-01 12:33:10

标签: .net garbage-collection c++-cli

考虑C ++ / CLI中的以下包装器,该包装器提供托管API并使用本机API(仅出于说明目的而使用C int):

public ref class A
{
public:

    A()
    {
        native = new int;
        *native = 0;
    }

    !A() // finalizer
    {
        delete native;
        native = nullptr;
    }

    ~A() // destructor
    {
        this->!A();
    }

    void Increase()
    {
        int *otherNative = native; // for illustrative purpose
        // (1) Garbage collector might work here
        *otherNative++; // (2) operation on native object
        // (3)
    }

private:
    int *native;
};

在C#中考虑一个简单的客户端:

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Increase();
    }
}

在代码中的(1)处,垃圾收集器可能会启动并收集 "不可到达的对象"。从书" Expert C ++ / CLI"作者:Marcus Heege(2007),也来自 https://blogs.msdn.microsoft.com/oldnewthing/20100813-00/?p=13153我了解到了这一点 "不可到达的对象"包括其唯一引用仍在范围内但不再使用的对象。 因此,在最后一个引用超出范围之前,可以对对象进行垃圾回收。 如果这让您感到困惑,请举例如下:

void Method()
  { 
      Y y = SomehowCreateY();
      int z = 123;
      y->m();
      z++; // "y" still in scope, but can be garbage collected here
      blabla();
  }

对于包装器示例,这意味着垃圾收集器可能会调用 在(1)和/或(2)期间或期间的终结器,因此本机对象将 在(2)中使用时或之前删除。

本书和博文都建议放GC.KeepAlive(this) 在示例代码中的(3)处以避免此问题。

所以基本上C ++ / CLI中对象活动的语义非常棘手,我们认为我们不能以这种方式编写可靠的包装器,因为我们很容易忘记编写GC.KeepAlive(this)

虽然我有很好的消息来源,这些棘手的语义确实存在,但这些来源 相当古老。我的问题:

  1. 在较新版本的C ++ / CLI中,这种棘手的语义仍然存在吗?
  2. 如果没有,我想要一个很好的参考,以便我能确定它,因为它很难测试。
  3. 如果是,是否有一种不易出错的方式来处理它?<​​/ li>

0 个答案:

没有答案