STL containers, SBO and user allocator conflicts

I recently played the development of a custom allocator based on a memory pool that is shared between multiple instances of a allocator.

It was assumed that the dispenser would be compatible with containers based on STL and Standard C ++, such as vector, deque, map, string, etc.

However, something in particular caused me some confusion. Various container implementations, such as std :: vector , std :: string , use Small Buffer Optimization β€” a stack-based allocation for small initial memory requirements.

For example, MSVC9.1 has the following member in the basic_string class:

union _Bxty { // storage for small buffer or pointer to larger one _Elem _Buf[_BUF_SIZE]; _Elem *_Ptr; char _Alias[_BUF_SIZE]; // to permit aliasing } _Bx; 

I don’t see how, when creating instances of such containers, you can persuade the implementation only and always use the provided allocator and not use SBO. I ask, because one of the intentions of custom allocators was to use them in a shared memory context, where the amount of shared memory might be less; the SBO restriction some of the various implementations might use.

For example, I would like to have a situation where I can have two instances of std :: string, one per process, sharing a common block of memory, which may be less than or equal to the top of the SBO limit.

Perhaps related: May std :: vector use a little buffer optimization?

 typedef std::vector<int,mysharedmemallocator> shmvtype; shmvtype v(2,0); //<-- if SBO then error as memory is allocated on //stack not via the allocator v[1] = 1234; //<-- if SBO then error as wrong piece of memory // is being modified. 

Let's look at another example that is not based on shared memory, as this seems to complicate some things. Suppose I want to specialize my std :: basic_string or std :: vector, etc. Using a allocator that fills the memory that it allocates with the value 0xAB before presenting the pointer back to the caller for some reason other than a whim.

A container that specializes in this new allocator, but which also uses SBO, will not have SBO-based memory filled with the 0xAB pattern. For example:

 typedef std::basic_string<char,myfillmemallocator> stype stype s; s.resize(2); assert(s[0] == 0xAB); // if SBO this will fail. 
+6
source share
1 answer

one of the intentions of implementing custom allocators was to use them in a shared memory context

It may be what you intend to do with it, but that is not why they exist. Indeed, with the exception of basic_string in C ++ 98/03, it is impractical to share the allocated memory between objects. They can share allocator objects, so they can get their memory from the same place. But for modifications of one object it is forbidden to influence another, which is not connected with each other; Each instance must be separate.

Lines with copy to write work only because the system assumes that any non-constant access to the symbol will be written to it, making a copy. And in C ++ 11 even basic_string forbidden to do such things as copy-on-write-style.

For example, I would like to have a situation where I can have two instances of std :: string, one per process, sharing a common block of memory, which may be less than or equal to the upper limit of SBO.

This is not possible without writing your own class. The allocator controls only the memory. What you want is a guaranteed string for copy to write or some common string class.

This requires a container class specifically designed for this purpose.

+4
source

All Articles