Prev: Is there any standard/guarantees for exception safety in STL operations?
Next: Is there any standard/guarantees for exception safety in STL operations?
From: Zeljko Vrba on 18 Jul 2010 05:29 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 18 Jul 2010 15:26 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 18 Jul 2010 20:55 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 19 Jul 2010 04:52
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! ] |