передача права собственности на объект на std :: allocator rebind - PullRequest
3 голосов
/ 09 мая 2011

У меня есть приложение Visual Studio 2008 C ++, в котором я выполняю замену стандартного распределителя, используемого в контейнерах, таких как std::vector. Но я столкнулся с проблемой. Моя реализация опирается на распределитель, владеющий дескриптором ресурса. В случае, если используется функция rebind, мне необходимо передать право владения дескриптором новому распределителю. Примерно так:

template< class T >
class MyAllocator
{
public:
    template< class U >
    explicit MyAllocator( const MyAllocator< U >& other ) throw() 
        :  h_( other.Detach() ) // can't do this to a `const`
    {
    };

    // ...

private:
    HANDLE Detach()
    {
        HANDLE h = h_;
        h_ = NULL;
        return h;
    };

    HANDLE h_;
}; // class MyAllocator

К сожалению, я не могу освободить старый распределитель от владения дескриптором, потому что это const. Если я удалю const из конструктора перепривязки, контейнеры его не примут.

error C2558: class 'MyAllocator<T>' : no copy constructor available or copy constructor is declared 'explicit'

Есть ли хороший способ обойти эту проблему?

Ответы [ 4 ]

2 голосов
/ 09 мая 2011

Не слишком много зная о распределителях (они никогда не нужны): ваш ctor-экземпляр принимает const ref, тем самым обещая не изменять объект other, но вы все равно пытаетесь его изменить.Хотя бывают случаи, когда классы были спроектированы таким образом (std::auto_ptr), это выглядит подозрительно.
Синтаксически, вы всегда можете объявить h_ mutable и сделать Detach() const функцией-членом, но явсерьез подвергал бы сомнению семантику этой установки, прежде чем взломать мой путь через синтаксические джунгли с помощью широкого меча.

1 голос
/ 12 мая 2011

Вы не можете передать владение, потому что распределитель может быть скопирован и восстановлен несколько раз, даже в одном контейнере, и полученные экземпляры используются одновременно.

Вместо этого вам придется поделиться ресурсом. Создайте косвенное указание для ресурса со счетчиком ссылок. Что-то вроде:

class SharedHandle {
    HANDLE h_;
    int count;
    SharedHandle(HANDLE h) : h_(h), count(1) {}
    ~SharedHandle() { CloseHandle(h_); } // or whatever to release the resource.
    SharedHandle *Ref() { ++count; return this; }
    void Unref() { if(!--count) delete this; }
}

и чем:

explicit MyAllocator( const MyAllocator< U >& other ) throw() 
:  h_( other.h_->Ref() )

В дополнение к контейнерам, которые, естественно, должны выделять гетерогенные блоки, такие как hash_map / unordered_map, известно, что реализация контейнеров Microsoft выделяет различные странные вещи. Когда я отслеживал выделения в одном приложении Windows, из STL исходило много распределений странных размеров.

1 голос
/ 12 мая 2011

Вы можете решить эту проблему с дополнительным уровнем косвенности, но это не идеальное решение.По сути, ваш распределитель будет иметь указатель на дескриптор, который будет размещен / освобожден в конструкторе / деструкторе.Дескриптор, на который он указывает, будет неконстантным, поэтому вы можете «переместить» дескриптор из одного распределителя в другой.Это действительно добавляет некоторые накладные расходы для распределителя.

Я не знаю вашего точного случая, но кажется, что распределитель с сохранением состояния, который нетривиально копируем, должен быть тщательно рассмотрен для всех его последствий.Есть ли альтернативный способ упростить его конструкцию, чтобы у него не было ручки только для перемещения?

1 голос
/ 09 мая 2011

Что произойдет, если вы объявите h_ как mutable?

...