2010-08-26 2 views
1

Я работаю с набором C API третьей стороны в C++, который имеет два методы беспокойства для этой дискуссии:Пользовательский распределитель для std :: vector <> с выпуском?

  1. Это эквивалентно таНос(): the_api_malloc (размер) (плюс соответствующий the_api_free())
  2. функция, в которой память создана с the_api_malloc() возвращается к тому, что имеет право собственности на него и the_api_free() 'ы это внутренне: the_api_give_back (PTR)

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

Что я хотел бы сделать, это иметь класс std :: vector type, который использует мой собственный распределитель, но также имеет метод 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 

UPDATE 2: Пытался создать MyOwningAllocator и MyNonOwningAllocator затем обменивать из владеющих на не владеющий где на «время выхода», но не может получить своп(), чтобы работать, как они отличаются типы.

ответ

1

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

+0

Аботаторы не имеют состояния, поэтому я не уверен, как у меня может быть флаг в одном? – NuSkooler

+0

@NuSkooler: точнее, стандартная библиотека не * требуется * для поддержки распределителей, имеющих состояние. Тем не менее, это первое, что я попробую. Если память используется, C++ 0x требует, чтобы они поддерживали генераторы с сохранением состояния, поэтому я бы предположил, что есть приличный шанс, что это сработает. Я бы сделал только что-то другое, если вы считаете, что это действительно необходимо. –

+0

Я создал release_ownership() в своем настраиваемом распределителе, который устанавливает значение члена bool. В deallocate() bool проверяется и ничего не делает, если true. Тем не менее, адрес всегда отличается между release_ownership() и deallocate(), поэтому bool всегда false (это значение по умолчанию ctor). – NuSkooler

1

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

+0

Является ли штраф исполнения swap() тяжелым? То, что я делаю все это, я могу использовать STL (например,vector <>) и C++, но когда пришло время, передайте данные на API C без a_api_malloc() и memcpy(). Если swap() - легкий вес, я полагаю, что у меня мог бы быть освобождающий совместимый распределитель для обмена в любом месте, о котором я раньше думал о вызове release()? – NuSkooler

+0

@NuSkooler: 'swap' очень, очень быстро. По порядку дюжины машинных циклов. Здесь я бы не попробовал пользовательский распределитель. Замените указатель, который получает управление с помощью «vector» (пустой перед заменой), замените 'release'' swap', и вы должны быть установлены. – Potatoswatter

+0

@Potatoswatter: Извините, если я здесь плотный: вы предлагаете мне поменять() из пользовательского распределителя (который использует the_api_malloc()) на стандартный вектор? Разве это не приведет к тому, что второй вектор попытается удалить память, когда он будет уничтожен? Если я полностью выведу пользовательский распределитель из памяти, память не будет выделена с помощью the_api_malloc(), и поэтому она не может быть освобождена by_api_give_back(). Может, мне здесь что-то не хватает? – NuSkooler