From: Zeljko Vrba on
In Dinkumware's reference, I found the following example:

===
For example, given an allocator object al of type A, you can allocate an object
of type Other with the expression:

A::rebind<Other>::other(al).allocate(1, (Other *)0)
===

I have written a pooled memory allocator that satisfies the std::allocator
interface. The destructor of my allocator releases the complete pool of
memory that it was managing, which makes the above example invalid - the
returned pointer becomes invalidated as soon as the temporary allocator
object gets destructed. On the other hand, the standard says nothing about
the expected behavior of the allocator's destructor.

What is this group's opinion on what the allocator's destructor should / is
allowed to do?

Is an instance of some_allocator<T> meant to persist through the whole
run-time of the program? Or is a program obliged to ensure that the
lifetime of the allocator exceeds the lifetime of the objects returned
by it?

If relevant, I intend to use my allocator with standard containers and possibly
also with Google's sparse hash.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 18 Jul., 22:29, Zeljko Vrba <mordor.nos...(a)fly.srk.fer.hr> wrote:
> In Dinkumware's reference, I found the following example:
>
> ===
> For example, given an allocator object al of type A, you can allocate an object
> of type Other with the expression:
>
> A::rebind<Other>::other(al).allocate(1, (Other *)0)
> ===
>
> I have written a pooled memory allocator that satisfies the std::allocator
> interface. The destructor of my allocator releases the complete pool of
> memory that it was managing, which makes the above example invalid - the
> returned pointer becomes invalidated as soon as the temporary allocator
> object gets destructed. On the other hand, the standard says nothing about
> the expected behavior of the allocator's destructor.
>
> What is this group's opinion on what the allocator's destructor should / is
> allowed to do?
>
> Is an instance of some_allocator<T> meant to persist through the whole
> run-time of the program? Or is a program obliged to ensure that the
> lifetime of the allocator exceeds the lifetime of the objects returned
> by it?

There does not exist such a general whole-run-time requirement.
Allocators are supposed to be EqualityComparable and the meaning
of two allocator objects being equal is, that one can deallocate
memory allocated by the other one.

Unfortunately this basically good idea was near to worthless in
C++03, because a second normative wording also said that
implementations of containers are permitted to assume that all
instances of an allocator of a given type are interchangeable
and thus must be equal to each other.

This relaxation of the rules has been removed as of C++0x and
implementations are now required to honor equality of allocator
objects.

In both C++03 and C++0x the so-called default allocator of type
std::allocator guarantees that two objects std::allocator<T> and
std::allocator<U> with T potentially different from U always
returns true for operator==.

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Zeljko Vrba on
On 2010-07-19, Daniel Krügler <daniel.kruegler(a)googlemail.com> wrote:
>
> There does not exist such a general whole-run-time requirement.
> Allocators are supposed to be EqualityComparable and the meaning
> of two allocator objects being equal is, that one can deallocate
> memory allocated by the other one.
>
I think that I haven't been clear enough about the issue.

With my allocator, given

Other *ptr = A::rebind<Other>::other(al).allocate(1, (Other *)0);

ptr is invalidated as soon as the "other" allocator is destructed (which is
basically at the end of the statement). This is because the destructor
of my
pooled allocator destroys the whole memory pool it was managing.

To reformulate the question: is the memory returned by an allocator object
supposed to outlive the allocator object itself?

[Dinkumware's example suggests that the answer is "yes", yet I haven't been
able to confirm that by quickly reading the allocator requirements in the
standard.]

>
> Unfortunately this basically good idea was near to worthless in
> C++03, because a second normative wording also said that
> implementations of containers are permitted to assume that all
> instances of an allocator of a given type are interchangeable
> and thus must be equal to each other.
>
I do not understand the wording in the standard "all instances of an
allocator
of a given type". Does "given type" refer to the template parameter
type or to
the whole allocator type? How do you interpret this sentence? I can
think of
two interpretations:

1) instances of A1<T> must be interchangeable
2) instances of A1<T> and A2<T> must be interchangeable

PS: another reason for the idea being almost worthless is because the
standard
permits that the containers assume that A<T>::pointer is equivalent to T*.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bo Persson on
Zeljko Vrba wrote:
> On 2010-07-19, Daniel Kr�gler <daniel.kruegler(a)googlemail.com>
> wrote:
>>
>> There does not exist such a general whole-run-time requirement.
>> Allocators are supposed to be EqualityComparable and the meaning
>> of two allocator objects being equal is, that one can deallocate
>> memory allocated by the other one.
>>
> I think that I haven't been clear enough about the issue.
>
> With my allocator, given
>
> Other *ptr = A::rebind<Other>::other(al).allocate(1, (Other *)0);
>
> ptr is invalidated as soon as the "other" allocator is destructed
> (which is basically at the end of the statement). This is because
> the destructor
> of my
> pooled allocator destroys the whole memory pool it was managing.
>
> To reformulate the question: is the memory returned by an allocator
> object supposed to outlive the allocator object itself?
>
> [Dinkumware's example suggests that the answer is "yes", yet I
> haven't been able to confirm that by quickly reading the allocator
> requirements in the standard.]

Probably.

An implementation that assumes that all instances are equivalent, can
very well create another copy later and use that instead:

A::rebind<Other>::other(al).deallocate(ptr, 1);

If the allocators compare equal, you should be able to allocate
through one and deallocate through another.


>
>>
>> Unfortunately this basically good idea was near to worthless in
>> C++03, because a second normative wording also said that
>> implementations of containers are permitted to assume that all
>> instances of an allocator of a given type are interchangeable
>> and thus must be equal to each other.
>>
> I do not understand the wording in the standard "all instances of an
> allocator
> of a given type". Does "given type" refer to the template parameter
> type or to
> the whole allocator type? How do you interpret this sentence? I
> can think of
> two interpretations:
>
> 1) instances of A1<T> must be interchangeable
> 2) instances of A1<T> and A2<T> must be interchangeable
>
> PS: another reason for the idea being almost worthless is because
> the standard
> permits that the containers assume that A<T>::pointer is equivalent
> to T*.

It is condition 1 that is assumed. For the default allocator it is
even worse, as std::allocator<T1> == std::allocator<T2> is always
true.


Bo Persson



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]