-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrect C++11 allocator model support #161
Comments
@glenfe, thanks for your feedback! I copied your items to check them off once they are fixed:
|
Started looking a little bit into this, gonna go through the list with questions:
The issue I see trying this is 2 fold:
Seems easy enough
Currently this is static, I would imagine for a reason? It doesn't make sense to return the stored allocator in that situation, so I imagine that would need to be changed to non-static? What was the initial reason to make this static? Additionally, should this return a reference now?
Again, has recursiveness, which I suspect would be OK by now. That said, this increases the size of a the object by quite a bit. The basic_json type is now going to be std::allocator larger, which isn't too bad until you realize that each object contains many others potentially.
Easy enough
Perhaps I'm being a little slow, but I don't really get what you mean here? Edit to add: I'll note that since the #169 pull request pushes the allocate-specification onto the user defining the ObjectType/ArrayType/StringType, would we perhaps be better off just removing the "create" mechanism entirely? Could we do without the AllocatorType entirely, and just ensure we recursively define the types of ObjectType/ArrayType/StringType such that their allocators will be used for all children? |
"rebind the stored allocator instance member variable" "This increases the size of a the object by quite a bit. The basic_json type is now going to be std::allocator larger" The way to avoid that is to derive from it instead of having it as a member. Then the empty base class optimization would cause it to take up no space when it is stateless. |
As Greg said, the way to avoid increasing storage by You could achieve that via inheritance, or by pairing the allocator instance with another member by leveraging a type like |
In C++11 and above, the
Now, given an object, |
Even |
This is an attempt to make it work with nlohmann#164. The thing is that the current code attempts to define containers with incomplete types, this is not supported by the standard and does not work unordered_map. std::vector and std::map work but we might be in the realm of undefined behavior.
This utility class facilitates use of the empty base optimization idiom: |
Update: I created a feature branch for custom allocators. |
IMHO it's reasonable to omit support for "fancy pointers" i.e. pointers that aren't just
No, because if there's no object constructed there yet then
|
@jwakely Good point. There is probably some acceptable approach involving p.operator->() when applicable (as I have observed Howard doing, in this place).
Agreed. Which is why I hope the |
Yep, that's the trick :-) Two overloads, one for raw pointers which just returns its argument, and one for everything else, which returns |
I have too little understanding of allocators. I started to incorporate the mentioned fixes a long time ago, but the library is a complex beast and I had to give up at some point. Any help is greatly appreciated, be it a pull request or any concrete idea how move forward on this issue. |
Here is a preliminary list of issues:
class AllocatorType = std::allocator<ValueType>
instead oftemplate<class U> class AllocatorType = std::allocator
. i.e. Do not require that the allocator type is a class template with one template parameter.basic_json
constructors should accept an optional allocator instance:basic_json(..., const AllocatorType& allocator = AllocatorType());
get_allocator()
member should return the value of that stored allocator instance.AllocatorType<Type> alloc;
, instead rebind the stored allocator instance member variable withstd::allocator_traits<AllocatorType>::rebind_alloc<Type> alloc(allocator);
.alloc.construct(...)
directly, instead usestd::allocator_traits<AllocatorType>::rebind_traits<Type>::construct(alloc, ...)
. Allocators are not required to provideconstruct
ordestroy
so all construction and destruction should go throughstd::allocator_traits
.pointer
so preserve those (instead ofT*
) for the result ofalloc.allocate(n)
. Usestd::addressof
with those pointers to obtain the value for use withconstruct(...)
.You'll notice all the C++ standard library facilities which support allocators implement the above, so look to them (or to allocator aware types in Boost) for further examples.
The text was updated successfully, but these errors were encountered: