Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RAII in C++/CLI

I'm used to the C++ RAII facilities, and I want to use RAII the right way with managed code in C++/CLI. Herb Sutter and Microsoft both tell me this is the best practice.

I have something like this:

ref struct Managed
{
    // No default constructor
    Managed( /*...*/ ) { /*...*/ }
    ~Managed() { /* Important non-managed resource release here */ }
    // ...
};

ref struct UsesManaged
{
    Managed^         m_;
    array<Managed^>^ a_;

    UsesManaged( Managed^ m, array<Managed^>^ a ) : m_(m), a_(a) {}
    // ...
};

ref struct Creator
{
    Managed^         m_;
    array<Managed^>^ a_;
    UsesManaged^     u_;

    Creator()
    {
        // Must allocate dynamically here, not in initializer list
        // because in my real code, I use "this" here for a callback.
        m_      = gcnew Managed( /*...*/ );
        a_      = gcnew array<Managed^>( 2 );
        a_[ 0 ] = gcnew Managed( /*...*/ );
        a_[ 1 ] = gcnew Managed( /*...*/ );
        u_      = gcnew UsesManaged( m_, a_ );
    }
};

I want (1) automatic resource destruction so I don't have to delete every gcnew'ed object manually, particularly in the face of exceptions; (2) the ability to share objects safely and clearly (passing around std::auto_ptr and the like doesn't qualify); and (3) the ability to have my class consumed by VB or C# and have the cleanup automatically run when the object goes out of scope (e.g., due to an exception).

In standard C++ I'd use std::shared_ptr and std::vector or similar facilities to automate RAII. Here, I could use STL/CLI's vector, but there is no shared_ptr equivalent. The only relevant C++/CLI smart pointer I see is the sparsely documented msclr::auto_handle, which is akin to std::auto_ptr, including transfer-of-ownership semantics, which are not compatible with vectors, though they'd work alright in an array.

What's the proper C++/CLI way to achieve my three goals? (Note also, my main C++/CLI class, Creator in the above, will be consumed by VB/C#.)

[Updates: Added links to Herb Sutter and MS at the top and added goal 3 (consumption by VB/C#).]

like image 692
metal Avatar asked Sep 10 '10 14:09

metal


1 Answers

You can have RAII with managed code: if you have this:

ref class A {
  ~A() { // implements/overrides the IDisposable::Dispose method
        // free managed and unmanaged resources here
   }
};


Then you can do this:

void foo()
{
  A a(cons_args); // stack-like usage
  // use a ...
}

and this will effectively be treated as:

void foo()
{
  try
  {
     A^ a_ = gcnew A(cons_args);
  }
  finally
  {
     a_->~A();
  }
}
like image 102
tragomaskhalos Avatar answered Oct 07 '22 18:10

tragomaskhalos