将非托管/非托管成员添加到托管 class

Adding unmanaged / non managed member to managed class

感谢您的关注。我是一些 VS2013 代码的新手,它是 C++ 和一些微软特定扩展的混合体。该代码有一个 class like

ref class Foo {
    Bar^ bar_; // somewhere else, bar_ = gcnew Bar...
};

现在我需要添加一个非托管成员,网上搜索好像可以

ref class Foo {
    Bar ^ bar_;
    Unmanaged* ptr_; // somewhere else, ptr = new Unmanaged();
    ~Foo() {
        this->!Foo();
    }
    !Foo() {
        delete ptr_;
        // do I need anything to deal with bar_?
    }
};

问题是:

1) 这是finalizer/destructor要走的路吗?

2) 既然我明确地写了 finalizer/destructor,我还需要为 bar_ 写任何额外的东西吗?

3) 有更简洁的方法吗?

1) is this finalizer/destructor the way to go?

是的。

2) do I need to write anything extra for bar_

片段中没有明显的内容。但是,如果 Bar class 也是一次性的,那么您可能应该将 delete bar_; 添加到析构函数中。不是终结器。如果您将引用传递给其他代码则不会,因此您无法确定此引用是最后一个仍在使用 Bar 对象的引用。

3) are there cleaner way to do it?

没有。有 其他 种方法。例如,您可以考虑不添加析构函数。拥有一个会给使用 class 的代码带来调用它的负担。通常是 C# 或 VB.NET 代码,它必须使用 using 语句或显式调用 Dispose()。请记住,他们经常忘记。或者没有好的调用方式

如果这样的代码预计不会创建大量 Foo 实例并且 Unmanaged class 仅使用一点内存,那么终结器可能就足够了。或者,如果 Foo 对象预计会在应用程序的整个生命周期内存在(这很常见),那么处置就毫无意义了。即使它确实使用大量内存,GC::AddMemoryPressure() 也是一个非常好的选择。让您的 class 更易于使用。

并且您可以考虑将 Unmanaged 指针包装在它自己的 class 中,这样 Foo 就不再需要终结器了。沿着 .NET 中 SafeHandle classes 的模式,SafeBuffer 是最接近的匹配项。这往往是矫枉过正,但是在 C++/CLI 包装器中,delete 尤其是失败是您不想隐藏的。

但是您所拥有的可以完成工作。