Topic: Allocators pointers
Author: "=?iso-8859-1?q?Ion_Gazta=F1aga?=" <igaztanaga@gmail.com>
Date: Fri, 12 Jan 2007 10:34:58 CST Raw View
Mathias Gaunard wrote:
> Ion Gazta aga wrote:
>
> > In theory, allocator::reference can be also a different type than B&.
>
> In the table of the C++ Standard draft, I can see
>
> expression | return type
> -------------------------------------
> X::reference T&
> X::const_reference T const&
>
> Doesn't that mean that allocator::reference is just an usual reference?
Yes. But this invalidates the use of smart pointers that can't be
converted to pointers. If the reference needs to be a usual reference,
that means that it can be converted to a pointer because
allocator<T>::reference ref = *smart_ptr;
X *raw_ptr = &ref;
Using smart pointers in C++ allocators is these days is pretty limited.
For example the construction function:
void construct(pointer ptr, const Type& _Val);
is quite inefficient and can make you make store more than 1 allocator
in your node containers. You can read more about this in a paper I
wrote (n2045):
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html
> Anyway I am having other problems with void allocators, because it is
> not possible to construct one from an allocator bound on another type.
> Therefore it is not possible to do:
>
> struct Foo {};
>
> template<typename Allocator = std::allocator<void> >
> Allocator::pointer allocate(Allocator& allocator)
> {
> typename Allocator::template rebind<Foo>::other alloc(allocator);
>
> Allocator::pointer p = alloc.allocate(1); // implicit
> conversion assumed
>
> allocator = Allocator(alloc); // in order to make the void
> allocator equal with the Foo one, which is needed to use it to
> deallocate the object -- it doesn't work however since 'allocator' is a
> void allocator, but would had worked on differently bounded allocators.
>
> return p;
> }
>
> It doesn't seem the allocator interface really considered the casting
> needs, be it with pointers or the allocators themselves.
I don't understand why you can't construct a void allocator from a
value allocator. What's the problem?
> I am not sure this is always possible.
> I believe the custom pointers of the allocator interface allowed
> allocating from other places than memory, files for example.
> How could one convert an iterator in a file (which would be the custom
> pointer type) from a pointer and vice versa?
Your reference type must be a raw reference, so you will surely be able
to do that.
> If getting a pointer was always possible though, that would allow to
> avoid allocator::construct and thus be able to do in-place construction,
> which it doesn't allow. (another problem of allocators)
Yes. In theory, if you are creating objects in a file, you can't use
in-place construction, even if a pointer to an object is convertible to
a raw poitner. You could overload operator-> to return a temporary
proxy bject where the user writes and after that, when the proxy is
destroyed, data is flushed to disk, but apart from being quite
complicated, the user can hold reference to the object, and you can't
inject your code there.
I'm try to be practical. Do you know any allocator::pointer which
refers to a file object (I'm not talking about memory mapping, that can
be solved with offset ptrs)? The only uses of allocators I've seen are
pools and they all use raw pointers. The only use of non-raw pointers
that I've seen is shared memory pointers or segmented memory pointers.
Allocators are one of those dark corners in C++. Even stateful
allocators are not supported in the standard since a container can
suppose that two allocators of the same type are equal.
> > Regarding casting functions: My opinion is that we should either fix
> > TR1 casting functions to make them ADL friendly or we should change the
> > language to allow casting operator overloading (just like we can do
> > with operator new).
>
> Allowing casting operator overloading seems like the best way to allow
> real smart pointers that behave like the real thing.
>
> However, I do not see how to make the casting functions ADL friendly.
> (modifying a smart pointer given as an argument rather than returning it?)
If those template functions are not found using ADL, we could use
overloading:
template<class Origin, class DestinityT>
smart_ptr<DestinityT> smart_static_cast (smart_ptr<Origin>, DestinityT
*);
the call would be very ugly in your generic code:
smart_ptr<Derived> pderived = ...
//This is for raw pointers
using std::smart_static_cast;
smart_ptr<Base> pbase = smart_static_cast(pderived, (Base*)0);
I would prefer static_pointer_cast to be usable in a generic way:
smart_ptr<Derived> pderived = ...
//Support raw pointers
using std::static_pointer_cast;
smart_ptr<Base> pint = static_pointer_cast <Base>(pderived);
However, this syntax is not similar to static_cast, where, the template
parameter is the target pointer type, not the value type. If we could
overload static_pointer_cast:
smart_ptr<Base> pint = static_pointer_cast<smart_ptr<Base>>(pderived);
This would allow also reinterpret_casts with smart pointers.
Regards,
Ion
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Mathias Gaunard" <loufoque@gmail.com>
Date: Sat, 13 Jan 2007 09:47:35 CST Raw View
Ion Gazta aga wrote:
> You can read more about this in a paper I
> wrote (n2045):
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html
Good to see that people are working on improving allocators.
I had always wondered why there was no distinction between node
allocation and array allocation.
Another problem, though way less important, is the fact that in order
to deallocate a pointer to a node, it is needed to have an allocator
bound on the same type as was used to allocate it.
Operator delete allows to delete with a pointer to a base type if the
destructor is virtual. It could be interesting if the language allowed
the virtual destructor to share the type information so that operator
delete is not the only one who can use it.
> I don't understand why you can't construct a void allocator from a
> value allocator. What's the problem?
While std::allocator<T> has both a constructor taking a
std::allocator<T> and a templated one on U taking a std::allocator<U>,
std::allocator<void> only has a constructor taking a
std::allocator<void> (compiler generated).
I believe this is a defect, since I see no reason why it should be like
this, especially since the allocator requirements don't talk about
this.
Something else, I think adding the possibility to allocate from a void
allocator, with a similar interface to new/delete and new[]/delete[],
would be interesting, especially if you only know at runtime the type
you're going to allocate.
>
> > I am not sure this is always possible.
> > I believe the custom pointers of the allocator interface allowed
> > allocating from other places than memory, files for example.
> > How could one convert an iterator in a file (which would be the custom
> > pointer type) from a pointer and vice versa?
>
> Your reference type must be a raw reference, so you will surely be able
> to do that.
>
> > If getting a pointer was always possible though, that would allow to
> > avoid allocator::construct and thus be able to do in-place construction,
> > which it doesn't allow. (another problem of allocators)
>
> Yes. In theory, if you are creating objects in a file, you can't use
> in-place construction, even if a pointer to an object is convertible to
> a raw poitner. You could overload operator-> to return a temporary
> proxy bject where the user writes and after that, when the proxy is
> destroyed, data is flushed to disk, but apart from being quite
> complicated, the user can hold reference to the object, and you can't
> inject your code there.
It seems making allocator::reference be a real reference seriously
restricts possibilities of allocators.
Thinking about it, I don't see how to implement allocator::address with
something that's supposed to store to files, unless the objects stored
are unique.
Why not allow it to be something else then?
Just like allocator::pointer must be defined as a smart pointer,
allocator::reference should then be defined as a smart reference
though. That would require defining exactly how smart pointers and
smart references work and how they provide similar functionality that
the real thing.
Dereferencing the pointer should probably return a smart reference.
> I'm try to be practical. Do you know any allocator::pointer which
> refers to a file object (I'm not talking about memory mapping, that can
> be solved with offset ptrs)? The only uses of allocators I've seen are
> pools and they all use raw pointers. The only use of non-raw pointers
> that I've seen is shared memory pointers or segmented memory pointers.
I've not seen any other allocators that the one you're talking about.
I don't even remember where I heard about that file stuff, maybe it was
before the standardization of C++.
> Allocators are one of those dark corners in C++. Even stateful
> allocators are not supported in the standard since a container can
> suppose that two allocators of the same type are equal.
For what reason are standard containers allowed to assert that?
It shouldn't cost them much to comply with the basic requirements. And
if it does, maybe a trait could be added to the allocator indicating
whether it meets the additional requirements or not.
Maybe that usage of traits could be extended, allowing allocators to
indicate whether they need to know what the type of the object or the
number of objects allocated are when deleting, or additional
restrictions about usage like only LIFO.
Those are just merely ideas to allow allocators to be more flexible
though, not performance issues that seriously need to be addressed.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Mathias Gaunard <loufoque@remove.gmail.com>
Date: Mon, 8 Jan 2007 19:28:08 CST Raw View
Allocators can use specific types for pointers.
According to the standard, it seems the only requirement (not
considering the additional ones) is that those must be random access
iterators.
However, how can we perform casting between different pointer types then?
If I need to do downcasting from a pointer to B b to a pointer to D, I
could do
allocator.address(static_cast<D&>(*b));
(Which can trigger UB, by the way)
But what if I have a void pointer, that I can't dereference, and I want
to cast it to a pointer to T?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "=?iso-8859-1?q?Ion_Gazta=F1aga?=" <igaztanaga@gmail.com>
Date: Thu, 11 Jan 2007 11:20:33 CST Raw View
Mathias Gaunard wrote:
> Allocators can use specific types for pointers.
>
> According to the standard, it seems the only requirement (not
> considering the additional ones) is that those must be random access
> iterators.
>
> However, how can we perform casting between different pointer types then?
> If I need to do downcasting from a pointer to B b to a pointer to D, I
> could do
> allocator.address(static_cast<D&>(*b));
In theory, allocator::reference can be also a different type than B&.
In practice, since we can't overload operator.(), your approach would
work. The problem with allocator::pointer, is that we don't have
standard casting functions.
Even the functions defined by TR1 smart pointers
(static_pointer_cast<>()...) are not enough to have pointer-agnostic
containers, because those functions can't be found using ADL, due to
their explicit template parameters (this issue is related with a core
issue, I think).
In my experience with shared memory offset pointers, you have two
approaches:
1) Your proposed code: use "reference" as a temporary to do the real
casting. Take in care that dynamic_cast with references might throw an
exception.
2) Suppose that smart pointers are convertible to raw pointers and the
inverse, and they have a get_pointer() function returning a raw pointer
that can be found via ADL and a constructor taking a raw pointer. In
this case, the real casting is done using raw pointers. If you want to
use smart pointers in other places than containers using allocators
(for example, intrusive containers) convertability from a raw pointers
is the only one that works, because you don't have
"allocator::address()". This approach works with raw pointers and I use
it with my shared memory and multi-segment shared memory pointers.
To sum up: the use of allocator::pointer is pretty unclear (although
it's very useful for many applications). I hope that the committee
clarifies this issue for the next standard.
Regarding casting functions: My opinion is that we should either fix
TR1 casting functions to make them ADL friendly or we should change the
language to allow casting operator overloading (just like we can do
with operator new).
Meanwhile, I think will need to stick to non-standard tricks.
Regards,
Ion
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Mathias Gaunard <loufoque@remove.gmail.com>
Date: Thu, 11 Jan 2007 15:38:39 CST Raw View
Ion Gazta aga wrote:
> In theory, allocator::reference can be also a different type than B&.
In the table of the C++ Standard draft, I can see
expression | return type
-------------------------------------
X::reference T&
X::const_reference T const&
Doesn't that mean that allocator::reference is just an usual reference?
> 1) Your proposed code: use "reference" as a temporary to do the real
> casting. Take in care that dynamic_cast with references might throw an
> exception.
What annoys me the most with this is the need to dereference, which can
be UB and doesn't work with void pointers (my main problem).
On the other hand, it seems rather standard conforming.
Anyway I am having other problems with void allocators, because it is
not possible to construct one from an allocator bound on another type.
Therefore it is not possible to do:
struct Foo {};
template<typename Allocator = std::allocator<void> >
Allocator::pointer allocate(Allocator& allocator)
{
typename Allocator::template rebind<Foo>::other alloc(allocator);
Allocator::pointer p = alloc.allocate(1); // implicit
conversion assumed
allocator = Allocator(alloc); // in order to make the void
allocator equal with the Foo one, which is needed to use it to
deallocate the object -- it doesn't work however since 'allocator' is a
void allocator, but would had worked on differently bounded allocators.
return p;
}
It doesn't seem the allocator interface really considered the casting
needs, be it with pointers or the allocators themselves.
>
> 2) Suppose that smart pointers are convertible to raw pointers and the
> inverse, and they have a get_pointer() function returning a raw pointer
> that can be found via ADL and a constructor taking a raw pointer. In
> this case, the real casting is done using raw pointers.
I am not sure this is always possible.
I believe the custom pointers of the allocator interface allowed
allocating from other places than memory, files for example.
How could one convert an iterator in a file (which would be the custom
pointer type) from a pointer and vice versa?
I admit though I have little knowledge about the application of
allocators, I am just trying to make my container allocator-aware but
couldn't even find simple guidelines on how to do so.
Various problems that I am having with them actually make me want to
rollback my own interface.
If getting a pointer was always possible though, that would allow to
avoid allocator::construct and thus be able to do in-place construction,
which it doesn't allow. (another problem of allocators)
> Regarding casting functions: My opinion is that we should either fix
> TR1 casting functions to make them ADL friendly or we should change the
> language to allow casting operator overloading (just like we can do
> with operator new).
Allowing casting operator overloading seems like the best way to allow
real smart pointers that behave like the real thing.
However, I do not see how to make the casting functions ADL friendly.
(modifying a smart pointer given as an argument rather than returning it?)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]