RAII в C ++ / CLI - PullRequest
       70

RAII в C ++ / CLI

7 голосов
/ 10 сентября 2010

Я привык к средствам RAII C ++ и хочу правильно использовать RAII с управляемым кодом в C ++ / CLI. Трава Саттер и Microsoft оба говорят мне, что это лучшая практика.

У меня есть что-то вроде этого:

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_ );
    }
};

Я хочу (1) автоматическое уничтожение ресурсов, поэтому мне не нужно удалять каждый объект gcnew'ом вручную, особенно при исключениях;(2) способность делиться объектами безопасно и четко (передача std :: auto_ptr и тому подобное не подходит);и (3) возможность использования моего класса VB или C # и автоматического запуска очистки, когда объект выходит из области видимости (например, из-за исключения).

В стандартном C ++ я использовал быstd :: shared_ptr и std :: vector или аналогичные средства для автоматизации RAII.Здесь я мог бы использовать вектор STL / CLI, но нет эквивалента shared_ptr.Единственный релевантный интеллектуальный указатель C ++ / CLI, который я вижу, это редко документированный msclr :: auto_handle , который похож на std :: auto_ptr, включая семантику передачи права собственности, которая несовместима с векторамиони будут работать хорошо в массиве.

Как правильно использовать C ++ / CLI для достижения моих трех целей?(Также обратите внимание, что мой основной класс C ++ / CLI, Creator в приведенном выше, будет использован VB / C #.)

[Обновления: добавлены ссылки на Херба Саттера и MS вверху и добавлена ​​цель 3 (потреблениепо VB / C #).]

Ответы [ 3 ]

2 голосов
/ 28 марта 2011

Я принимаю правильный ответ на свой вопрос как Комментарий Билли ONeal к чьему-либо ответу:

Ах, ты не можешь этого сделать. Здесь нет способ заставить сборщик мусора уничтожить объект. Увидеть blogs.msdn.com / б / oldnewthing / Архив / 2010/08/09 / 10047586.aspx Правильный способ сделать это - потребовать явный закрытый вызов, и поставить вызов к этому в финализаторе. Если для по какой-то причине клиентский код не очистить, GC будет (в конце концов) очистить его для вас (в программе прекращение, если ничего больше), но вы не может написать код, который зависит от тот. - Билли ONEAL 10 сентября 10 в 16: 02

Помимо ссылки, которую он дает, см. Также здесь и здесь .

2 голосов
/ 10 сентября 2010

Вы можете иметь RAII с управляемым кодом: если у вас есть это:

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


Тогда вы можете сделать это:

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

и это будет эффективно рассматриваться как:

void foo()
{
  try
  {
     A^ a_ = gcnew A(cons_args);
  }
  finally
  {
     a_->~A();
  }
}
1 голос
/ 10 сентября 2010

Не проверено, но это должно помочь вам начать:

template<typename T>
value class counted_handle
{
    ref struct Count { int refCount; Count() : refCount(1) {} };
    T^ m_sharedHandle;
    Count^ m_sharedCount;

    void release() { if (m_sharedCount && 0 == --sharedCount->refCount) delete m_sharedHandle; m_sharedCount = nullptr; m_sharedHandle = nullptr; }
    void addref( if (m_sharedCount) ++m_sharedCount->refCount; }
public:
    counted_handle() : m_sharedHandle(nullptr), m_sharedCount(nullptr) {}
    counted_handle(T^ handle) : m_sharedHandle(handle), m_sharedCount(gcnew Count()) {}
    counted_handle(counted_handle<T>% src) : m_sharedHandle(src.m_sharedHandle), m_sharedCount(src.sharedCount) { addref(); }
    void ~counted_handle() { release(); }
    counted_handle<T>% operator=(counted_handle<T>% src) { src.addref(); release(); m_sharedHandle = src.m_sharedHandle; m_sharedCount = src.m_sharedCount; }
    counted_handle<T>% operator=(T^ handle) { release(); m_sharedHandle = handle; m_sharedCount = gcnew Count(); }
}
...