1

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?

Walter
  • 44,150
  • 20
  • 113
  • 196
  • 1
    Make a custom deleter as part of your `raw_memory` object? – Tony The Lion Sep 17 '12 at 09:54
  • 3
    If you don't need allocator support, you could use `std::unique_ptr p(std::malloc(n), std::free);`. – Kerrek SB Sep 17 '12 at 10:03
  • 1
    I guess you mean `typename allocator::value_type`? – juanchopanza Sep 17 '12 at 10:18
  • @juanchopanza yes, of course. corrected. – Walter Sep 17 '12 at 10:24
  • @KerrekSB I don't really need allocator support, but would like to be able to require the alignment of the raw memory. So I could instead use an integer template parameter requesting the alignment. That would avoid the allocator stuff ... thanks. – Walter Sep 17 '12 at 10:27
  • 1
    OK, just replace `std::free` with `myfree`, and write your own handler function that deduces the location of the original address that needs to be passed to `free`. You could write your own cookie-type marker for the general case, and use `posix_memalign` where available. – Kerrek SB Sep 17 '12 at 11:39
  • 4
    You don't have to force the user to pass an allocator that traffics in `char` types. A conforming allocator has a nested template named `rebind` that will produce an allocator that handles whatever type you instantiate `rebind` with. – Pete Becker Sep 17 '12 at 13:22

1 Answers1

2

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.
Uri London
  • 10,631
  • 5
  • 51
  • 81
  • `std::vector` has a constructor that takes a `const allocator&`, i.e. it is **not** required to take a non-constant `allocator&` as you suggest. – Walter Sep 19 '12 at 19:45
  • @Walter - you are correct. I tried to avoid having a member for the allocator (which would only make sense if you didn't have resize). I modified my answer so raw_memory has its own allocator (constructed as a copy of the argument allocator), and the closure for the delete function now has the 'this' pointer – Uri London Sep 19 '12 at 20:50