简体   繁体   中英

Can I use allocator specified for some type to allocate objects of another type in C++?

Some container A has a template parameter Alloc (that is a template too) representing an allocator type. A specifies Alloc for the type A::Node .

template <template <T> Alloc>
class A {
    struct Node {
    };

    Alloc<Node> allocator_; // the allocator object
};

Please excuse me for possibly wrong C++ code above.

So, allocator_.allocate(1) will allocate sizeof(A::Node) bytes. But during operation, container A needs a memory for some object of other than A::Node type, say a temporary string (of char s).

From technical point of view, I could use existing allocator in such a dirty way:

 size_t string_len = 500;
 // how much objects spanned in memory is enough to fit our string?
 size_t equal_size = (string_len / sizeof(Node)) + 1;

 auto mem = allocator_.allocate(equal_size);
 char *p = (char*)mem; // reinterpret cast
 // ... use p to store the string ... memcpy(p, str_src, str_len); //

 // Now p is not needed, so return memory to allocator: 
 allocator_.deallocate(mem, equal_size); 

Is there a less dirty approach, considering I need no more than 1 allocator and I wish to put all the memory management to it?

All this comes from those needs:

  • to have a single allocator that could be killed to free all (possibly leaked) memory that A is allocated for any its purposes during operation
  • to have not more than 1 allocator (including the default ::new, ::delete)

std::allocator has a member type rebind for exactly that purpose:

std::allocator<Node> alloc;

std::allocator<Node>::rebind<char>::other char_alloc;

char * mem = char_alloc.allocate(string_len);

You can use an allocator's rebind for this. From this documentation :

A structure that enables an allocator for objects of one type to allocate storage for objects of another type.

it is built exactly for your case - taking an allocator type oriented to one type, and building the corresponding one oriented to some other type.

In your case, it might look like

typename Alloc<T>::rebind<Node>::other allocator_;

You should probably use Alloc::rebind member template to get an allocator for that another object.

However, that does mean that you do have 2 allocators. The advantage of rebind is to allow the user of your template to specify the allocator type only for a single allocated type.

Also note that rebind is optional, so if you must support such allocators, you'll need to pass the other allocator as an argument, but you can still use the rebound allocator as a default value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM