Добавление функциональности в оболочку ручки - PullRequest
0 голосов
/ 09 ноября 2009

У меня есть класс C ++ RAII для управления РУЧКАМИ Win32 с использованием boost :: shared_ptr <>, который выглядит примерно так:

namespace detail {
struct NoDelete { void operator()( void* ) {}; };
}; // namespace detail

template< typename HANDLE_TYPE, typename HANDLE_DELETER >
class CHandleT
{
public :
    explicit CHandleT( HANDLE_TYPE handle, bool delete_on_release = true )
    {
        if( delete_on_release )
            handle_ = Handle( handle, HANDLE_DELETER() );
        else
            handle_ = Handle( handle, detail::NoDelete() );

    };

    operator HANDLE_TYPE() const { return static_cast< HANDLE_TYPE >( handle_.get() ); };

protected:
    typedef boost::shared_ptr< void > Handle;
    Handle handle_;

}; // class CHandleT

struct DeallocateHandle
{
    void operator()( void* handle ) { ::CloseHandle( handle ); };
};

typedef CHandleT< HANDLE, DeallocateHandle > CHandle;

Я бы хотел расширить его так, чтобы вместо этого было написано:

CHandle my_handle( ::CreateEvent( NULL, FALSE, FALSE, NULL ) );
::SetEvent( my_handle.get() );

Я мог бы написать:

CEvent my_event( NULL, FALSE, FALSE, NULL );
my_event.SetEvent();

Будет ли лучший способ сделать это - использовать класс CHandle в качестве члена класса CEvent?

class CEvent
{
public:
    explicit CEvent( LPSECURITY_ATTRIBUTES lpEventAttributes = NULL,
                     BOOL bManualReset = TRUE,
                     BOOL bInitialState = FALSE,
                     LPCTSTR lpName = NULL, 
                     bool delete_on_release = true ) :
        handle_( new CHandle( ::CreateEvent( lpEventAttributes, 
                                              bManualReset, 
                                              bInitialState, 
                                              lpName ),
                               delete_on_release ) )
    {
    };

    BOOL SetEvent()
    {
        _ASSERT( NULL != handle_ && NULL != handle_.get() );
        return ::SetEvent( handle_.get() );
    };

private:
    boost::shared_ptr< CHandle > handle_;
}; // class CEvent

Или есть способ получше? (Обратите внимание, что я все еще хочу сохранить семантику копирования CHandle, заданную boost :: shared_ptr <>.

Спасибо, PaulH

Ответы [ 2 ]

3 голосов
/ 09 ноября 2009

Я не буду вдаваться в дискуссии о boost :: shared_ptr или каких-либо умных ptr. И вот несколько причин, почему с разных точек зрения между линиями, и почему умные указатели всегда и всегда могут быть сокращены или выбиты.

Код, похоже, эмулирует модель CLR и NT, и в этом случае ОС предопределяет семантику того, что вы делаете. Он называется :: DuplicateHandle, и он хорошо работает и больше подходит для межпроцессных сценариев (и может взломать меньше, чем boost :: interprocess или аналогичный). И это применимо к нескольким другим контекстам.

Теперь второй, надеюсь, не противоречивый момент, когда наследством бедного старого ОО пренебрегают, потому что фокус сдерживания регулярно выигрывает (хотя на самом деле он не имеет ничего общего с ОО, когда вы играете за дополнения для тех, кто постоянно кричит: содержать меня). Поэтому независимо от того, насколько редким это может быть, или является ли оно аргументом OO, не OO или O (o): «наследование» выигрывает здесь.

Почему? Поскольку это концепция ожидаемого дескриптора, включающая в себя событие Win32, Mutex, виды автоматического сброса, Thread, все это, кроме cris_section (которое также имеет задний дескриптор глубоко внутри, но специально обрабатывается как в CLR, так и в NT, плюс двойственный характер). Таким образом, это имеет абсолютный смысл для:

typedef CHandleT WaitHandle;

быть корнем «иерархии» вместе с семантикой копирования того, чем является базовая реализация.

Наконец, это обеспечивает наиболее эффективное представление ваших типов данных, которые являются дескрипторами, поскольку они будут имитировать операционную систему, на которую вы нацеливаетесь, и не нуждаются ни в подсчете ссылок, ни в лавинном / пульсации.

Затем пришла кроссплатформенная разработка и поддержка :: многопоточность и разрушила историю перед сном: -)

2 голосов
/ 10 ноября 2009

Вам не нужно хранить дескриптор в CEvent как shared_ptr. Дескриптор уже используется атрибутом CHandleT.

Композиция хороша, если вы не хотите использовать элементы CEvent в качестве элементов CHandleT (используя полиморфизм).

...