1

I have a type with the following structure:

class Block
{
   /* few fixed size fields*/
   ...

   /* fixed size byte array*/
   std::unique_ptr<std::uint8_t[]> data;
}

These objects are used in a work pipeline and there are gonna be a lot of such objects. Size of data is a runtime parameter, but it's known before work starts and it doesn't change later.

I want to use a memory pool (boost::pool/boost::object_pool in particular) to preallocate a lot of such objects with the such layout that each Block object is followed by it's data array.

How can I achieve this?

CodingFeles
  • 374
  • 5
  • 18
  • Actually, I'm not sure yet whether unique_ptr will be useful in this case. – CodingFeles Dec 12 '18 at 14:18
  • The issue is that the object size now varies... So I would say custom allocator, but that's a hammer... Why do you want contiguous Block and data? – Matthieu Brucher Dec 12 '18 at 14:37
  • @MatthieuBrucher well, it's variable in general sense. But with the solution logic it's determined at the start and doesn't change. Contiguous block and data are needed for better cache locality. There are batches of such blocks which will be processed one after another. – CodingFeles Dec 12 '18 at 14:45
  • In that case, you don't want block to be in that memory, but only data. That's a custom allocator. – Matthieu Brucher Dec 12 '18 at 14:47
  • Why? Even though data is a main thing, block have fields which also will be used in processing. – CodingFeles Dec 12 '18 at 14:55
  • OK, let's assume you do want that. You need a custom allocator for both block and data. – Matthieu Brucher Dec 12 '18 at 14:56
  • Custom allocator seems the right thing. Can you make make it an answer? Maybe with a bit more details for easier research? :) Also, I'd like to hear reasons why I wouldn't want block to be with data together. I think you may know something that I don't. I'd be happy, if you could explain to me (in the chat, of course). – CodingFeles Dec 12 '18 at 15:03

1 Answers1

2

I think your only option is to write a custom allocator on top of your boost::pool and use it to get pointers to the memory. You can have a first start by looking at How to use boost::pool library to create a custom memory allocator for writing such an allocator.

Basically this custom allocator will allocate a large array of memory (at least one) and give back pointers to blocks and data with boost::pool. Modify the first answer of the previous post so that it doesn't rely on the size of T, but on a custom size passed as a paremeter. This size should be sizeof(Block) + data_length.

Now, what you could do is cheat and change your class:

class Block
{
    uint8_t* data;
};

Now when you ask for a new Block, you don't get just your Block, you also get the data block afterwards. When you construct your object (placement new), pass also the pointer to the new data (that would be the return of the allocator + sizeof(Block).

When the data is freed, don't forget to first call the destructor as this is required for placement new.

Of course, there are still lots of small details that you will have to solve, but this should give you a start.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62