Пользовательский распределитель для std :: vector <> с выпуском? - PullRequest
2 голосов
/ 27 августа 2010

Я работаю с C API стороннего разработчика, установленным на C ++, для которого обсуждаются два метода:

  1. Это эквивалентно malloc (): the_api_malloc (размер) (плюс соответствующий the_api_free ())
  2. Функция, в которой возвращается память, созданная с помощью the_api_malloc (), которая получает ее и внутреннюю принадлежность the_api_free (): the_api_give_back (ptr)

Я создал собственный распределитель, обертывающий the_api_malloc () и the_api_free () для использования, например, с std :: vector. Это прекрасно работает.

То, что я хотел бы сделать, это иметь класс типа std :: vector, который использует мой пользовательский распределитель, но также имеет метод release (), который при вызове освобождает владельца своей памяти и поэтому не будет вызывать мои пользовательские распределители the_api_free ().

pointer release() /* pointer is of T* */

Пример использования:

MyClass myClass(1024); // the_api_malloc()'s 1024 bytes
// ... do something with myClass
the_api_give_back(myClass.release());

Я не уверен, что лучший способ это осуществить. То, что я сейчас имею в качестве эксперимента, довольно неприятно:

class MyClass : public std::vector<char, MyAllocator<char> > {
public:
    using typename std::vector<char, MyAllocator<char> >::pointer;

    pointer release() {
        // note: visual studio impl.
        pointer p = this->_Myfirst;
        this->_Myfirst = 0;
        this->_Mylast = 0;
        this->_Myend = 0;
        return p;
    }
}

Есть ли лучший способ?

ОБНОВЛЕНИЕ 1 : Вот то, что я пробовал, основываясь на предложениях ниже. Это также должно помочь проиллюстрировать желаемое поведение и где оно в настоящее время терпит неудачу.

template <class T>
class MyAllocator
{
public:
  // types omitted for clarity

  MyAllocator() : m_released(false) { }

  template <class U>
  MyAllocator(MyAllocator<U> const& a) : m_released(a.m_released) { }

  // other ctors, dtors, etc. omitted for clarity

  // note: allocate() utilizes the_api_malloc()

  void deallocate(pointer p, size_type num)
  {
    if(!m_released) {
      the_api_free(p);
    }
  }

  void release_ownership() { m_released = true; }

  bool m_released;
};

template <typename T>
char* ReleaseOwernship(T& container)
{
  container.get_allocator().release_ownership();
  return &container[0];
}

// usage:
{ // scope
  std::vector<char, MyAllocator<char> > vec;

  // ...do something to populate vec...

  char* p = ReleaseOwnership(vec);
  the_api_give_back(p); // this API takes ownership of p and will delete it itself
} // end scope - note that MyAllocator::deallocate() gets called here -- m_release is still false

ОБНОВЛЕНИЕ 2: Попытка создания MyOwningAllocator и MyNonOwningAllocator с последующим переключением из владения в не принадлежащее, где во время «выпуска», но не может заставить работать swap (), поскольку они отличаются типы.

Ответы [ 2 ]

1 голос
/ 27 августа 2010

vector::swap переведет владение выделенным блоком другому vector. Тем не менее, нет способа остановить вектор от вызова vector::allocator_type::deallocate в его деструкторе, и нет переносимого способа прямого изменения внутренних указателей.

1 голос
/ 27 августа 2010

Вместо того, чтобы пытаться остановить вектор от вызова свободной функции распределителя, я бы включил ваш release в качестве члена вашего распределителя и установил флаг.Когда флаг установлен, the_api_free просто вернется (т.е. будет действовать как nop).

...