Question

I need to write a function to retrieve and process some data. This data may be allocated in several ways (on the data segment, on the heap, on a shared memory segment and so on):

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

Since data may be dynamically allocated, I'd think that the best way to handle it is using an unique_ptr or some other kind of smart pointers. However it's not always dynamically allocated: I'd need to choose at runtime the deleter for unique_ptr, but that's not possible.

How should I define and handle data?

Was it helpful?

Solution

You could make the custom deleter take a run-time value!

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});

OTHER TIPS

I'm not sure about std::unique_ptr, but you can use std::shared_ptr. Its custom deleter doesn't depend on class template parameter.

In addition to KennyTm's good answer, another possibility is to use a function pointer as your deleter, and then supply different functions at run time:

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.
}

Use your own smart pointer with a deleter you choose:

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);
};

If you use a shared shared_ptr<> you can choose the deleter at runtime. As long as you don't copy/... the shared_ptr it should behave the same as a unique_ptr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top