Re: [boost] Re: Boost memory management guidelines
--- Gregory Colvin [EMAIL PROTECTED] wrote: [...] Apropos of which, I now think that the Boost UserAllocator requirements should be the default for components that parameterize how they use memory, with the Standard Allocator requirements being used only for components that need what they offer: a potentially very efficient way to allocate large numbers of small objects of known type, and/or a way to access storage via proxied pointers. Perhaps the boost allocator requirements should just combine both, the UserAllocator and StandardAllocator requirements. In a way, StandardAllocators can be considered as an extension of UserAllocators. Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
--- David Abrahams [EMAIL PROTECTED] wrote: But indeed allocate/construct/deallocate/destroy is more work than ^^^^ Oyeah. These two absolutely don't belong in allocator, period. Do any implementations even use them? Allocators exist to provide a point of customization for users, but you cannot/should not customize these. [...] The class getting constructed/destroyed has full control over that or the language is utterly bustificated. I think construct/destroy can be implemented as non-customizable static functions in boost just for convinence. static template typename A typename A::pointer construct( A a, size_t n ) { typename A::pointer p = a.allocate(n) try { p = new(p) A::value_type[n]; } catch(...) { a.deallocate( p, n ); } return p; } Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 05:42 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: On Monday, Sep 1, 2003, at 14:48 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: Conforming containers had better use them. I'm sorry, but I think that's flat wrong. What do you suppose that entry in column 2 of the allocator requirements table (20.1.5) means, after all? It means any value returned by construct, destroy, or deallocate goes unused. And once you are down in the coal mine customizing what a pointer is, I'm not sure you won't need to customize how to construct and destroy. The class getting constructed/destroyed has full control over that or the language is utterly bustificated. Yes, but the allocator may want to do something else as well, and construct and destroy serve as hooks for whatever that may be. Regardless, there is absolutely _nothing_ in the standard AFAICT which indicates the containers must use the allocator's construct and destroy, and several implementations in fact do not. Well then, I consider the standard broken in that regard. But we are off the topic that started this thread. Apropos of which, I now think that the Boost UserAllocator requirements should be the default for components that parameterize how they use memory, with the Standard Allocator requirements being used only for components that need what they offer: a potentially very efficient way to allocate large numbers of small objects of known type, and/or a way to access storage via proxied pointers. I think part of my point was that *nobody* needs what they offer, if you include construct/destroy. Or rather that some implementations have failed to use what they offer, and our standard unfortunately doesn't insist that they do. Another reason construct is needed is that Allocator::pointer might be a proxy, with operator* and operator- but not necessarily a conversion to void* or even T*. In fact, construct requires undefined behavior for non-POD T because you can't copy its T* argument which points into raw storage. I don't understand what you mean by this. Are you claiming that it is undefined to copy just a pointer to raw storage? If so, then how is placement new not undefined? The standard says: a.construct(p,t) Effect: new((void*)p) T(t) I think I would rather see a MPL lambda expression or metafunction class interface for allocator type parameters. It makes little sense for the allocator's user to be choosing its value_type. Something like: some_allocator_1 or struct select_allocator { template class T struct apply { typedef some_allocatorT type; }; }; with some_allocator's interface being like what's required for std::allocator but not including misplaced interface bits such as address/construct/destroy, and possibly max_size -- these can be added by a std::allocator facade wrapper if neccessary. I'm not sure we need a simple version and a complicated version. I'm not clear how you intend the above to be used, or what you intend it to be a replacement for. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 09:22 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: I think part of my point was that *nobody* needs what they offer, if you include construct/destroy. Or rather that some implementations have failed to use what they offer, and our standard unfortunately doesn't insist that they do. It's not unfortunate if it adds nothing, which is what I believe. Another reason construct is needed is that Allocator::pointer might be a proxy, with operator* and operator- but not necessarily a conversion to void* or even T*. Doesn't matter; you can always get the address of an object. See http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#390 So you would rather use this than use construct? template typename T T* addressof(T v) { return reinterpret_castT*( const_castchar(reinterpret_castconst volatile char (v))); } In fact, construct requires undefined behavior for non-POD T because you can't copy its T* argument which points into raw storage. I don't understand what you mean by this. Are you claiming that it is undefined to copy just a pointer to raw storage? Unless the pointer has the right type, yes. In which case the A::pointer return from A::allocate() is already undefined behavior? ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 09:22 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: ... Dave: I think I would rather see a MPL lambda expression or metafunction class interface for allocator type parameters. It makes little sense for the allocator's user to be choosing its value_type. Something like: some_allocator_1 or struct select_allocator { template class T struct apply { typedef some_allocatorT type; }; }; with some_allocator's interface being like what's required for std::allocator but not including misplaced interface bits such as address/construct/destroy, and possibly max_size -- these can be added by a std::allocator facade wrapper if neccessary. I'm not sure we need a simple version and a complicated version. I'm not clear how you intend the above to be used, or what you intend it to be a replacement for. I intend it to be the sort of type parameter that gets passed to our objects which need custom allocation in place of a standard allocator. It's ridiculous, IMO, to pass allocatorT to a node-based container which is *never* going to allocate a T object. But given rebind() it doesn't really matter. We could just as well have specified that all containers take allocatorvoid arguments. The container itself should decide which type the allocator template gets instantiated on, via: mpl::applympl::lambdaS, Node::type [ this is approximately the same as: S::template applyU::type == some_allocatorU except that it works when S is the lambda expression some_allocator_1 as well as when it's the select_allocator metafunction class below it. ] Sorry, but I'm still not following this, but that may be because I don't know much MPL, so I can only guess at what you are up to. I probably need a detailed example of how to write and use one of these thingys to make any sense of your proposal. Does your proposal support stateful allocators? What the rebind requirement in the allocator means for pool allocation, for example, is that a pool_allocatorT object must either be stateless (in which case allocator inequality is meaningless) Yes, all stateless allocators compare equal, and stateless allocators are the easiest kind to make compare equal, as the standard currently requires allocators to do. or effectively be able to allocate blocks of *any* size and alignment, rather than just as appropriate for T. Yes, because node-based containers need to allocate nodes, perhaps of various kinds, but they don't expose their node types in their interface. So you have to pass in something, and we went with T rather than void or whatever. It might have been better to have different allocator interfaces for array-based versus node-based containers, since array-based containers have no need of rebind(), and node-based containers have no need of allocatorT. It's a conceptual mess. Alex didn't have MPL when he invented allocators. So they are messier than they need to be, but I still say they are not so bad as you claim, and that it would be easier for the next standard to repair them than to replace them. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
--- David Abrahams [EMAIL PROTECTED] wrote: [...] Just how do you propose to prevent people from writing their own construct/destroy functions? And if they write an allocator from scratch, but *don't* provide construct/destroy manually, where will they come from? What I meant is that if boost allocators won't include constuct/destroy, all boost developers will probably implement their own construct/destroy helper functions (outside allocators) to construct/destroy object using allocators. In such case, I suggested to include standard construct/destroy functions in boost (not in allocators). Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 11:22 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: On Tuesday, Sep 2, 2003, at 09:22 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: I think part of my point was that *nobody* needs what they offer, if you include construct/destroy. Or rather that some implementations have failed to use what they offer, and our standard unfortunately doesn't insist that they do. It's not unfortunate if it adds nothing, which is what I believe. Another reason construct is needed is that Allocator::pointer might be a proxy, with operator* and operator- but not necessarily a conversion to void* or even T*. Doesn't matter; you can always get the address of an object. See http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html#390 So you would rather use this than use construct? template typename T T* addressof(T v) { return reinterpret_castT*( const_castchar(reinterpret_castconst volatile char (v))); } As long as it's packaged away and I don't have to look at the implementation. A customization point like an allocator should not be required to supply boilerplate that's always going to be the same. You are assuming that there was no good reason to allow an allocator to hook construct and destroy, for instance to do some bookkeeping. When I need to find out what I need to implement in order to customize allocation, I don't want to have to read through something which is 50% irrelevant to the task, as the allocator requirements are. Which is why I'm now suggesting that Boost UserAllocator is a better default. But in some cases, like the shared_ptr feature request that got me thinking on this, what you want is just to have objects allocate their internals using the same allocator as the container they are being placed in, in which case you don't need to implement an allocator, just call get_allocator(). n fact, construct requires undefined behavior for non-POD T because you can't copy its T* argument which points into raw storage. I don't understand what you mean by this. Are you claiming that it is undefined to copy just a pointer to raw storage? Unless the pointer has the right type, yes. In which case the A::pointer return from A::allocate() is already undefined behavior? Wow. Yes, IIUC. DR, I guess. I'm reeling from the implication that the following is undefined behavior for non-POD T: T* p = (T*)malloc(sizeof T); Are you sure? ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
--- David Abrahams [EMAIL PROTECTED] wrote: [...] I think construct/destroy can be implemented as non-customizable static functions in boost just for convinence. I think the word static is not what you meant, and is what led me to challenge the suggestion. I used word 'static' because I assumed that construct/destroy functions would be implemented in some 'memory' data type (just to qualify it). struct memory { static template typename A typename A::pointer construct( A a, size_t n ) {...} static template typename A void destroy( typename A::pointer ) {...} }; Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
Gregory Colvin wrote: You are assuming that there was no good reason to allow an allocator to hook construct and destroy, for instance to do some bookkeeping. I'm curious. Have you ever seen such an allocator? I've always assumed that construct/destroy/pointer are a but someone might need to do that feature that nobody has ever used. Then again, the Dinkumware implementation dutifully calls construct and destroy, paying (and forcing me to pay) the abstraction penalty price... so maybe I'm wrong, and construct/destroy are useful? ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 11:39 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: On Tuesday, Sep 2, 2003, at 09:22 America/Denver, David Abrahams wrote: ... I think you're missing my point. There's no reason that a stateful allocatorT should have access to the state data required to allocate U objects, but that's the status quo. I'm probably missing your point, but the idea is that a container needs to allocate various kinds of things, and they all get allocated with the same allocator, either directly or via rebind. For instance, maybe you are are using memory-mapped files as a persistent storage. The Ts and the Us and whatever the container needs all have to go into the same file, so the allocatorT and all its rebinds must know which file to use and how. ... It's a conceptual mess. Alex didn't have MPL when he invented allocators. So they are messier than they need to be, but I still say they are not so bad as you claim Are you saying my factual claims are wrong, or just that all those issues don't amount to a very important problem? Just that it doesn't look nearly as messy to me as it does to you. and that it would be easier for the next standard to repair them than to replace them. That may be, but we're here at Boost, talking about the interface we should be using in Boost components. Yep. I still think UserAllocator is a good default, and that where it doesn't suffice there is some value to playing nicely with STL. So even when we come up with some beautiful new thing to do the allocation job better, we will still need adaptors both ways, so that one can get an allocator from an STL container and turn it in to one of our new things, or take one of our new things and turn it into an allocator to use in an STL container. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 12:27 America/Denver, Peter Dimov wrote: Gregory Colvin wrote: You are assuming that there was no good reason to allow an allocator to hook construct and destroy, for instance to do some bookkeeping. I'm curious. Have you ever seen such an allocator? I've always assumed that construct/destroy/pointer are a but someone might need to do that feature that nobody has ever used. I've heard allocators described that probably used construct() to navigate efficiently from a proxy pointer to the raw memory in which to construct. But I never saw the code. Then again, the Dinkumware implementation dutifully calls construct and destroy, paying (and forcing me to pay) the abstraction penalty price... so maybe I'm wrong, and construct/destroy are useful? I don't see that there need be any performance price for what Dinkumware does, or is that not what you mean by abstraction penalty? ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 13:00 America/Denver, Peter Dimov wrote: Gregory Colvin wrote: On Tuesday, Sep 2, 2003, at 12:27 America/Denver, Peter Dimov wrote: Then again, the Dinkumware implementation dutifully calls construct and destroy, paying (and forcing me to pay) the abstraction penalty price... so maybe I'm wrong, and construct/destroy are useful? I don't see that there need be any performance price for what Dinkumware does, or is that not what you mean by abstraction penalty? I'm not saying that there need be any price in a perfect world. I am saying that in practice, on the compiler I use, there is a price, like calling a non-inline destroy() O(N) times for a value_type that has an inline, empty, nonvirtual destructor. Or even for a built-in value_type. That is most unfortunate. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 12:51 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: On Tuesday, Sep 2, 2003, at 11:22 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: So you would rather use this than use construct? template typename T T* addressof(T v) { return reinterpret_castT*( const_castchar(reinterpret_castconst volatile char (v))); } As long as it's packaged away and I don't have to look at the implementation. A customization point like an allocator should not be required to supply boilerplate that's always going to be the same. You are assuming that there was no good reason to allow an allocator to hook construct and destroy, for instance to do some bookkeeping. The fact that nobody's required to use construct and/or destroy is testament to that. Thanks to the weasel-wording nobody's required to use much of anything besides allocate, deallocate, and rebind. That doesn't mean there was no point to all the rest in the original design. When I need to find out what I need to implement in order to customize allocation, I don't want to have to read through something which is 50% irrelevant to the task, as the allocator requirements are. Which is why I'm now suggesting that Boost UserAllocator is a better default. But in some cases, like the shared_ptr feature request that got me thinking on this, what you want is just to have objects allocate their internals using the same allocator as the container they are being placed in, in which case you don't need to implement an allocator, just call get_allocator(). Is it enough for all of Boost? It's probably overkill for some things. If so, great! If not, we still need to think about what a more-sophisticated interface looks like. Only if UserAllocator is inadequate? Also, if shared_ptr only needs to allocate at construction time (I'm not sure of this) we can avoid storing the allocator at all. Then how to deallocate? I'm reeling from the implication that the following is undefined behavior for non-POD T: T* p = (T*)malloc(sizeof T); Are you sure? Nope. 3.8/5 shows that I'm wrong. That's a relief. It still doesn't make any sense to return a T* from allocate since normally with a non-singular T* p, either p == 0 or *p refers to a constructed T. The idea was that AllocatorT::pointer might be a proxy type that cannot be converted to void* and back, so allocate() must return and construct() must take an AllocatorT::pointer rather than a void*. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 13:18 America/Denver, E. Gladyshev wrote: --- Gregory Colvin [EMAIL PROTECTED] wrote: Yep. I still think UserAllocator is a good default, and that where it doesn't suffice there is some value to playing nicely with STL. So even when we come up with some beautiful new thing to do the allocation job better, we will still need adaptors both ways, so that one can get an allocator from an STL container and turn it in to one of our new things, or take one of our new things and turn it into an allocator to use in an STL container. Am I right in trying to summarize your suggestion about UserAllocator? If you want to parametrize how a boost class manages memory, use UserAllocator parameter. Unless you need the standard Allocator interface. 1. The allocator parameter should implement the UserAllocator interface. 2. All instances of UserAllocator must be equal and stateless. The Boost pools use UserAllocator only as a type parameter. It is not required to be constructible or comparable. 3. If your class is using STL containers, use boost::memory::allocator adapter (see bellow). Why not just use std::allocator? 4. To construct/destroy objects, use boost::memory::construct/destroy. See below. 5. Avoid using explicit references to allocators. ... Usage example: == template typename T, typename UserAllocator = boost::default_user_allocator_new_delete class X { What if you want X to use the same allocator as some other STL container constructed with a non-Boost allocator? That would be difficult unless you have templatetypename T, class StdAllocator = std::allocatorT struct X { X(const StdAllocator); Also, it might sometimes be desirable, as it is for shared_ptr, to defer the choice of allocator until construction time: templatetypename T struct X { templateclass StdAllocator = std::allocatorT X(const StdAllocator); Or, if UserAllocator suffices: templatetypename T struct X { templateclass UserAllocator X(); T* _p; Leading underscores are a no-no. std::vectorT, boost::memory::allocatorT, UserAllocator _v; X() { _p = boost::memory::constructT, UserAllocator( 1 ) How to pass arguments to T's constructor? Better just p = new(UserAllocator::malloc(sizeof T)) T(...) } ~X() { if( _p ) boost::memory::destroyT, UserAllocator( _p, 1 ); In which case, why not just p-~T(), UserAllocator::free(p); ? } }; Eugene ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Tuesday, Sep 2, 2003, at 15:00 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: Also, if shared_ptr only needs to allocate at construction time (I'm not sure of this) we can avoid storing the allocator at all. Then how to deallocate? Using the custom deleter? Which will need to store a copy of the allocator, unless one takes advantage of the weasel wording that lets you instantiate a new one for the purpose. ... It still doesn't make any sense to return a T* from allocate since normally with a non-singular T* p, either p == 0 or *p refers to a constructed T. The idea was that AllocatorT::pointer might be a proxy type that cannot be converted to void* and back, so allocate() must return and construct() must take an AllocatorT::pointer rather than a void*. Wow, creepy. Yes. But unless you grant the desire to support such creepy beasts then not much of Allocator makes any sense. And such beasts can do useful work, like persistent stores and shared memory. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: Also, if shared_ptr only needs to allocate at construction time (I'm not sure of this) we can avoid storing the allocator at all. Then how to deallocate? Using the custom deleter? The deleter takes care of the pointee, but we are talking about the count. I think. I still find the list shared_ptrX hypothetical example where everything needs to use the same custom allocator somewhat artificial. In custom allocator situations I find vector X* a somewhat better choice since it has much less overhead. But I may be wrong. :-) ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
--- Gregory Colvin [EMAIL PROTECTED] wrote: [...] 3. If your class is using STL containers, use boost::memory::allocator adapter (see bellow). Why not just use std::allocator? Because boost::memory::allocator will use UserAllocator under the covers. So if you customized UserAllocator parameter, you customized how STL allocate their memory as well. 4. To construct/destroy objects, use boost::memory::construct/destroy. See below. 5. Avoid using explicit references to allocators. ... Usage example: == template typename T, typename UserAllocator = boost::default_user_allocator_new_delete class X { What if you want X to use the same allocator as some other STL container constructed with a non-Boost allocator? That would be difficult unless you have [...] Yes. T* _p; How to pass arguments to T's constructor? Better just p = new(UserAllocator::malloc(sizeof T)) T(...) } ~X() { if( _p ) boost::memory::destroyT, UserAllocator( _p, 1 ); In which case, why not just p-~T(), UserAllocator::free(p); ? The boost::memory::construct/destroy are just convinience wrappers that will do like just that. They can also handle exceptions properly. struct memory { template typename T, typename A static void destroy( T* p ) { try { p-~T(); A::free(p); } catch( ... ) { A::free(p); //free memory even if the destructor crashes. throw; } } }; Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
--- Gregory Colvin [EMAIL PROTECTED] wrote: [...] T* _p; Leading underscores are a no-no. I didn't see it in boost naming convention docs. Have I missed it? Some STL implmentations use leading underscores for members. Eugene __ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
Gregory Colvin wrote: [...] Two small corrections: shared_ptr currently uses std::allocator to allocate counts regardless. No, it uses plain new/delete by default. It is possible to get it to use std::allocator via a #define. [...] versus standard Allocator Allocator::pointer p = allocator.allocate(sizeof T); allocator.construct(p,T()); ... allocator.destroy(p); allocator.deallocate(sizeof T); allocate(1) and deallocate(p, 1) if I'm not mistaken. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Sunday, Aug 31, 2003, at 13:13 America/Denver, David Abrahams wrote: Gregory Colvin [EMAIL PROTECTED] writes: But indeed allocate/construct/deallocate/destroy is more work than ^^^^ Oyeah. These two absolutely don't belong in allocator, period. Do any implementations even use them? Allocators exist to provide a point of customization for users, but you cannot/should not customize these. Conforming containers had better use them. I'm sorry, but I think that's flat wrong. What do you suppose that entry in column 2 of the allocator requirements table (20.1.5) means, after all? It means any value returned by construct, destroy, or deallocate goes unused. And once you are down in the coal mine customizing what a pointer is, I'm not sure you won't need to customize how to construct and destroy. The class getting constructed/destroyed has full control over that or the language is utterly bustificated. Yes, but the allocator may want to do something else as well, and construct and destroy serve as hooks for whatever that may be. Using allocator is even more work than allocating raw memory with malloc and doing placement new and explicit destruction, then freeing the raw memory. That's my biggest complaint. It's new/delete T* p = new T(); ... delete p; versus malloc/free T* p = (T*)malloc(sizeof T); When you need malloc(sizeof(T) + N) Allocators get a lot harder to use. Agreed. new(p) T(); ... p-~T(); free(p); versus Boost UserAllocator T* p = (T*)user_allocator::malloc(sizeof T); new(p) T(); ... p-~T(); user_allocator::free(p); versus standard Allocator Allocator::pointer p = allocator.allocate(sizeof T); allocator.construct(p,T()); ... allocator.destroy(p); allocator.deallocate(sizeof T); Oops! There's a pointer missing here. Silly me for not compiling my email. Just a small example of why I'm saying it's a harder interface. Very small. Allocator has strange requirements, like p shall not be null. Another performance optimization. In most cases there is no way that p could be null in the first place, so why waste time checking? If I need to build a custom one I have to navigate rebind and the implications of allocator inequality for which the standard provides little guidance. Agreed. The Boost UserAllocator is easier to implement and to use. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Boost memory management guidelines
On Sunday, Aug 31, 2003, at 13:51 America/Denver, Peter Dimov wrote: Gregory Colvin wrote: [...] Two small corrections: shared_ptr currently uses std::allocator to allocate counts regardless. No, it uses plain new/delete by default. It is possible to get it to use std::allocator via a #define. OK. Anyway, the std::allocator interface is adequate for shared_ptr. [...] versus standard Allocator Allocator::pointer p = allocator.allocate(sizeof T); allocator.construct(p,T()); ... allocator.destroy(p); allocator.deallocate(sizeof T); allocate(1) and deallocate(p, 1) if I'm not mistaken. You are not. I shouldn't post uncompiled code late at night. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost