2012-03-02 3 views
2

Мне нужно написать функцию для извлечения и обработки некоторых данных. Эти данные могут быть распределены по нескольким направлениям (в сегменте данных, в куче, на сегменте разделяемой памяти и так далее):C++: unique_ptr с unknow deleter

T *data; 
if(global) data = &d; 
if(heap) data = new T [ size ]; 
if(shm) data = (T*) shmat(id, 0, 0); 
// processing data ... 

Поскольку data может быть динамически распределяемой, я думаю, что лучший способ для обработки используется unique_ptr или некоторые другие интеллектуальные указатели. Однако это не всегда динамически распределяется: мне нужно будет выбрать во время выполнения дебетера для unique_ptr, но это невозможно.

Как определить и обработать data?

+3

Интересного родственного чтение: [На пути к лучшему распределителю модель] (http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cts=1330701318745&ved=0CCYQFjAA&url=http%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22 % 2Fwg21% 2Fdocs% 2Fpapers% 2F2005% 2Fn1850.pdf & е = А-RQT-DXBeXA0QGJqqXFDQ & USG = AFQjCNFS07GH0af749GIyOIjE-QCC-K7dw & Sig2 = hBWQcfg-EUOmH2d8UI5UuQ). Это частный случай, когда тип делетера, являющегося частью этого типа, нарушает использование 'unique_ptr' с разными типами дебетов с помощью одной функции ... Моя рекомендация: используйте' shared_ptr', поскольку он выполняет стирание стилей на делетере. .. –

ответ

6

Вы можете сделать заказное удаление забегом времени выполнения!

struct MyCustomDeleter 
{ 
    MemoryType type; 
    template <typename T> 
    void operator()(T* value) const 
    { 
     switch (type) 
     { 
     case MemoryType::heap: 
      delete[] value; 
      break; 
     case MemoryType::shm: 
      unmap_from_shm(value); 
      break; 
     // etc. 
     } 
    } 
}; 

... 

std::unique_ptr<T, MyCustomDeleter> ptr (new T[size], 
             MyCustomDeleter{MemoryType::heap}); 
+0

Я использовал решение, подобное тому, которое вы предложили решить мою проблему. Во всяком случае, моя часть кода выглядит очень уродливо ... Я собираюсь задать новый вопрос в ближайшие дни о том, как реально реализовать это. Благодаря! :) – peoro

1

Используйте свой собственный интеллектуальный указатель с Deleter вы выбираете:

enum DataPointerType 
{ 
    Stack, 
    Dynamic, 
    SharedMem, 
    ... 
}; 

template <class T> 
class DataPointer 
{ 
public: 
    DataPointer(T* pointer, DataPointerType type) 
     : _ptr(pointer), _type(type) 
    { } 

    ~DataPointer() 
    { 
     switch (type) { 
     case Stack: break; 
     case Dynamic: delete _ptr; _ptr = nullptr; break; 
     ... 
     } 
    } 

    T& operator*() { return *_ptr; } 
    const T& operator*() const { return *ptr; } 

    T* operator->() { return _ptr; } 
    const T* operator->() const { return ptr; } 

private: 
    T* _ptr; 
    DataPointerType _type; 

    // Prevent copying and destruction, dangerous 
    DataPointer(const DataPointer& other); 
    DataPointer& operator=(const DataPointer& other); 
}; 
3

Я не уверен std::unique_ptr, но вы можете использовать std::shared_ptr. Его пользовательский делектор не зависит от параметра шаблона шаблона.

+2

Это работает, но имеет дополнительные накладные расходы сверх того, что необходимо для версии 'unique_ptr', которая набирает стирание на делете. Дополнительные приращения и декременты при сохранении ссылочного счета, вероятно, не имеют значения, но это потокобезопасные приращения и декременты. Тем не менее, лучше использовать это в первый проход, чем написать свой собственный умный указатель спереди, прежде чем вы это узнаете. – bames53

+0

@ bames53: В том случае, если это важно, я бы выбрал пользовательский делетер, как предложил KennyTM, возможно, немного измененный, чтобы взять функтора. –

1

Если вы используете общий shared_ptr<>, вы можете выбрать дебетер во время выполнения. Пока вы не копируете/... shared_ptr, он должен вести себя так же, как unique_ptr.

+0

Конечно, часть значения 'unique_ptr' заключается в том, что она предотвращает случайное копирование. – bames53

3

В дополнении к хорошему ответу KennyTm, другая возможность состоит в том, чтобы использовать указатель на функцию в качестве Deleter, а затем поставить различные функции во время выполнения:

typedef std::unique_ptr<T, void(*)(void*)> Ptr; 
void delete_global(void*); 
void delete_heap(void*); 
// etc. 

Ptr get(/* whatever */) 
{ 
    if (...) 
     return Ptr(data, delete_global); 
    if (...) 
     return Ptr(data, delete_heap); 

    // etc. 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^