C ++ / CLI资源管理混淆

时间:2012-02-09 21:17:57

标签: memory-management interop c++-cli

我对C ++ / CLI中的资源管理非常困惑。我认为我有一个句柄(没有任何双关语),但我偶然发现了auto_gcroot<T>类,同时查看了头文件,这导致了谷歌搜索,然后是阅读文档的更好部分,现在混乱。所以我想我会转向社区。

我的问题涉及auto_handle / stack语义和auto_gcroot / gcroot之间的区别。

  1. auto_handle:我的理解是这将清理托管函数中创建的托管对象。我的困惑是,垃圾收集者不应该为我们这样做吗?这不是托管代码的重点吗?更具体一点:

    //Everything that follows is managed code
    void WillThisLeak(void)
    {
        String ^str = gcnew String ^();
        //Did I just leak memory? Or will GC clean this up? what if an exception is thrown?
    }
    
    void NotGoingToLeak(void)
    {
        String ^str = gcnew String^();
        delete str;
        //Guaranteed not to leak, but is this necessary? 
    }
    
    void AlsoNotGoingToLeak(void)
    {
        auto_handle<String ^> str = gcnew String^();
        //Also Guaranteed not to leak, but is this necessary? 
    }
    
    void DidntEvenKnowICouldDoThisUntilToday(void)
    {
        String str();
        //Also Guaranteed not to leak, but is this necessary? 
    }
    

    现在这对我来说是有意义的,如果它是C#using keyword的替代品,并且它只推荐用于像Bitmap这样的资源密集型类型,但是这在文档中的任何地方都没有提到,所以我担心我一直在泄漏记忆这一整个时间

  2. auto_gcroot

  3. 我可以将它作为参数传递给本机函数吗?副本会发生什么?

        void function(void)
        {
            auto_gcroot<Bitmap ^> bmp = //load bitmap from somewhere
            manipulateBmp(bmp);
            pictureBox.Image = bmp;  //Is my Bitmap now disposed of by auto_gcroot?
        }
    
        #pragma unmanaged
    
        void maipulateBmp(auto_gcroot<Bitmap ^> bmp)
        {
            //Do stuff to bmp
            //destructor for bmp is now called right? does this call dispose?
        }
    

    如果我使用了gcroot,这会有用吗?

    此外,使用auto_handle和auto_gcroot有什么好处?他们似乎做了类似的事情。

    我必须误解一些事情才能使这一点变得毫无意义,所以一个好的解释会很棒。此外,关于正确使用这些类型的任何指导,我可以去学习这些东西的地方,以及我能找到的任何更好的做法/地方都将非常感激。

    非常感谢, 最大

1 个答案:

答案 0 :(得分:20)

  1. 记住调用托管对象的delete类似于在C#中调用Dispose。所以你是对的,auto_handle允许你做你在C#中用using语句做的事情。它确保在范围结束时调用delete。所以,不,如果你不使用auto_handle(垃圾收集器负责),你不会泄漏托管内存,你只是没有调用Dispose。如果您处理的类型没有实现IDisposable,则无需使用auto_handle。

  2. 当您想要保留本机类中的托管类型时,将使用gcroot。您不能使用帽^符号直接在本机类型中声明manged类型。你必须使用gcroot。这是一个“垃圾收集根”。因此,当gcroot(本机对象)存在时,垃圾收集器无法收集此对象。当gcroot被销毁时,它会释放引用,垃圾收集器可以自由地收集对象(假设它没有其他引用)。你在上面的方法中声明了一个独立的gcroot - 只要你可以使用hat ^语法。

  3. 所以你什么时候使用auto_gcroot?当您需要在本机类中保留manged类型并且该托管类型恰好实现IDisposable时,将使用它。在销毁auto_gcroot时,它将做两件事:在托管类型上调用delete(将其视为Dispose调用 - 没有释放内存)并释放引用(因此类型可以被垃圾收集)。

    希望它有所帮助!

    一些参考文献:

    http://msdn.microsoft.com/en-us/library/aa730837(v=vs.80).aspx

    http://msdn.microsoft.com/en-us/library/481fa11f(v=vs.80).aspx

    http://www.codeproject.com/Articles/14520/C-CLI-Library-classes-for-interop-scenarios