передача права собственности на объект при std:: повторная привязка распределителя

#c #standard-library #allocator

#c #стандартная библиотека #распределитель

Вопрос:

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

 template< class T >
class MyAllocator
{
public:
    template< class U >
    explicit MyAllocator( const MyAllocator< U >amp; 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'
  

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

Комментарии:

1. Разве распределители не обязаны не иметь состояния?? Где-то есть классическая статья Мэтта Остерна о распределителях, IIRC, но я не могу ее сейчас найти…

2. Вот статья: http://drdobbs.com/cpp/184403759 . И при беглом взгляде на это обсуждение кажется, что распределители с отслеживанием состояния действительно поддерживаются, хотя поддержка реализаций std lib раньше была проблемой.

3. @sbi — Спасибо вам за статью и обсуждение. У меня собирался возникнуть следующий вопрос о том, как обращаться std::swap .

Ответ №1:

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

Ответ №2:

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

Ответ №3:

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

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

Ответ №4:

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

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

 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 >amp; other ) throw() 
:  h_( other.h_->Ref() )
  

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