
Ion Gaztañaga ha escrito:
Hi Joaquín,
Joaquín Mª López Muñoz wrote:
[...]
b. I've casually inspected the code of B.IP and seems like the allocator construct/destroy interface is *not* actually used, see for instance list_alloc in boost/interprocess/containers/list.hpp
This was recently changed due to the restrictive nature of construct() (only copy construction, :-( ). I returned to placement new construction. Some committee members kindly requested my opinion when Matt's paper appeared and I just said that it was possible to use Interprocess without construct and destroy as long as the smart pointer is generically convertible (say, using ADL friendly get_pointer or requesting smart pointers to have a .get() member function to extract the raw pointer. The smart pointer is required to be constructible also from pointers to avoid also calling "address()" and other unuseful functions. Documentation of Boost.Interprocess is outdated and should reflect the new requirements.
So, if condition 3 is not used, I wonder what the actual requirements are with respect to allocator::pointer. I guess the main assumption B.IP containers work on is that allocator::pointer is implicitly convertible to/from T*.
Well, offset_ptr is not implicitly convertible to T* but is constructible (no explicit constructor) from a raw pointer. Implicit convertibility to a raw pointer was a major source of problems (you know that conversion operators are really tricky). Now the only requirement for the container is to use a generic function to extract the raw pointer. I've chosen to follow shared_ptr interface:
--> A smart pointer has a function called "get()" to extract the raw pointer. --> A smart pointer defines a function called "get_pointer()" to do the same that can be found with ADL.
Why this hassle? Cannot you just use: T* raw=&*p; ?? This looks *far* more generic than requiring compliant smart pointers to go with get or get_pointer.
In theory, the ADL option is appropriate, but in practice ADL is quite a big nightmare for some compilers. Well, that's because I don't really understand ADL ;-)
So the requirements for B.IP allocator::pointer are the same for those for B.Intrusive (which are not well explained):
I guess these should also be corrected, since one of the requirements reads: "It must be convertible to a raw pointer and constructible from a raw pointer." which as you just stated is not what's actually assumed. Also, I can't finally figure out if you're requiring *implicit* or *explicit* construction from T*.
Also, what the requirements are when handling (nonraw) pointers to types other than T? Consider the following:
struct T { X x; };
If I've got an allocator::pointer pt to an object t of type T and want to store a nonraw pointer to x, how should I do? I guess something like:
allocator::rebind<X>::other::pointer px=pt->x;
You could use rebind and also request compatibility with Boost pointer_to_other<> utility. pointer_to_other is just more convenient to write and independent from the allocator.
Both techniques are not equivalent... Nothing prevents one from providing, for instance, an allocator family whose pointer typedef is raw for some types an belongs to a class template X<...> for some other, thus breaking the pointer_to_other<> utility. If I were to standardize what kind of exotic allocators STL might support, I'd go with rebind.
Although in theory making the pointer convertible from/to a raw pointer might seem restrictive for some theoretical applications of allocators (the famous but not yet implemented containers allocating nodes on disk), in practice I haven't seen such restrictions. For example, can std::vector use std::copy to copy elements pointed by an smart pointer when reallocating the buffer? Or it should destroy the elements with allocator::destroy and construct them again with allocator::construct?
My choice is to bring allocator::pointer requirements down to the earth. Convertibility to raw pointers also offers the advantage of using static_cast which are essential when trying to optimize node containers.
but this is just a guess from my part, as it's not documented. Some clarifications on these issues, and maybe a rewriting of the relevant doc sections, would be welcome for those container writers willing to become B.IP allocator compatible.
I completely agree. I just was not expecting someone to write B.IP compatible containers yet and this was on my low priority queue.
If you need a partenaire to discuss the issue with, please consider me a volunteer. As it currently stands (see N2284), the standard does not provide any clue as to what kind of allocators other than the regular ones STL implementors are encouraged to support (it merely states that these non-regular allocators might "encapsulate more general memory models and [...] support non-equal instances.") It'd be nice if we can come up with a concrete proposal to add to this encouragement section --otherwise it's almost impossible that future STL implementations might ever support B.IP!!
Are you trying to make B.MI compatible B.IP? That's going to make some programmers really happy ;-)
I'm beginning to survey the terrain :) Joaquín M López Muñoz Telefónica, Investigación y Desarrollo