Walter
Walter

Reputation: 45414

managing raw memory with std::unique_ptr in C++

I want to have a little class which manages raw memory with this API

template<class allocator = std::allocator<char> >
class raw_memory
{
   static_assert(std::is_same<char, typename allocator::value_type>::value,
                 "raw_memory: allocator must deal in char");
public:
   raw_memory() = default;
   raw_memory(raw_memory&&) = default;
   raw_memory&operator=(raw_memory&&) = default;
   explicit raw_memory(size_t, allocator const& = allocator());
   ~raw_memory();       // deletes any memory
   char*get();          // returns pter to (begin of) memory
   void resize(size_t); // re-allocates if necessary, may delete old data
   size_t size() const; // returns number of bytes currently hold

   raw_memory(raw_memory const&) = delete;
   raw_memory&operator=(raw_memory const&) = delete;
   raw_memory(raw_memory&) = delete;
   raw_memory&operator=(raw_memory&) = delete;
};

The template parameter allocator allows for different memory alignment options.

I was thinking about using std::unique_ptr<char, Deleter>, as a member (or base) (plus a size_t holding the number of bytes). What to use as Deleter? Or is there a better way to achieve all that?

Upvotes: 1

Views: 1685

Answers (1)

Uri London
Uri London

Reputation: 10797

Since you let the users of your class to specify an allocator as a type argument, you must reference this argument for both allocation and deallocation. For this reason, the commend made by @Kerrek (although tricky and nice usage of pointer to function) is invalid, because you do want to use the allocator methods passed as an argument.

Using unique_ptr can work for you. As you correctly commented you must provide your own deleter, and per my comments above, it must be based on the allocator class passed as an agument to your template.

SIDE NOTE: Please be aware you have a syntax error in your template declaration. See my sample code below for the correct syntax (i.e. you must have the keyword 'template'):

template< class A = std::allocator<char> >
class raw_memory
{
private:
    A m_al;
    std::unique_ptr< char, std::function<void(char*)> > m_buffer;

public:
    raw_memory( size_t size, const A& al = A() )
        :m_al(al)
        ,m_buffer( m_al.allocate(size), [this, size](char* ptr){ m_al.deallocate(ptr,size); } )
        {
        }
};

Few things to note:

  • I'm using A as the type argument (I find it more readable to use all capital letters for tymplate argument).
  • Using c++11 Lambda notation, I'm passing a deleter functor to the constructor of unique_ptr. This functor has a closure state (a reference to al, and the size), which will be used during delete. In the closure I'm putting the this pointer (required to access m_al) and the size - both by value.

Upvotes: 2

Related Questions