![]() |
|
|
Welcome to the { mindfrost82.com } forums. You are currently viewing our boards as a guest which gives you limited access to view most discussions and access our other features. By joining our free community you will have access to post topics, communicate privately with other members (PM), respond to polls, upload content and access many other special features. Registration is fast, simple and absolutely free so please, join our community today! If you have any problems with the registration process or your account login, please contact contact us. |
|
|||||||
![]() |
|
|
LinkBack | Thread Tools | Search this Thread | Display Modes |
|
|||
|
[allocator.concept] smart pointer clarifications
I am currently writting a smart pointer which is reasonnably stable and I
decided supporting allocators for completion because of its increase in efficiency when the same pool used by containers is shared. I was told the new standards are being finalized and I am hoping minor but important changes could be applied before anything else. To give a quick overview on the current status of this topic, you will find below the latest text relating to allocator member functions (n2641). We see over there there are no dictinction between the pointer type returned by allocate() and the pointer type expected by deallocate() and destroy(). This is a big problem because this logic doesn't make sense anymore if smart pointers are to be used. Smart pointers are owners of their objects and aren't in no way going to give away external access to its object. We need these functions to use 1) distinct pointer type from the one returned by allocate() 2) make the parameter (pointer) passed as a non-const reference The latter is necessary to make changes to either the smart pointer itself or the object pointed to in case raw pointer are used. We can see my personnal implementation here and I would like to propose the following function signatures: template <typename T> class shifted_allocator { public: typedef shifted<T> value_type; typedef shifted_ptr<T> pointer; typedef shifted_ptr<const T> const_pointer; value_type * allocate(size_type s, const void * = 0); void deallocate(pointer & p, size_type); void construct(value_type * p, const T & x); void destroy(pointer & p); ... }; ** Allocator member functions ** 1) pointer X::allocate(size_type n); pointer X::allocate(size_type n, const_generic_pointer hint); Effects: Memory is allocated for n objects of type value_type but the objects are not constructed. [Footnote: It is intended that a.allocate be an efficient means of allocating a single object of type T, even when sizeof(T) is small. That is, there is no need for a container to maintain its own "free list". - end footnote] The optional argument, p, may Returns: A pointer to the allocated memory. [Note: If n == 0, the return value is unspecified. If n > 1, the means by which a program gains access to the second and subsequent allocated objects is determined outside of the Allocator concept. See RandomAccessAllocator, below, for one common approach. - end note] Throws: allocate may raise an appropriate exception. Remark: The use of hint is unspecified, but intended as an aid to locality if an implementation so desires. [ Note: In a container member function, the address of an adjacent element is often a good choice to pass for the hint argument. - end note ] 2) void X::deallocate(pointer p, size_type n); Preconditions: All n value_type objects in the area pointed to by p shall be destroyed prior to this call. n shall match the value passed to allocate to obtain this memory. [Note: p shall not be singular. - end note] Throws: Does not throw exceptions. 3) void X::destroy(pointer p); Effects: Calls the destructor on the object at p but does not deallocate it. Regards, -Phil -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Re: [allocator.concept] smart pointer clarifications
"Phil Bouchard" <phil@fornux.com> wrote in message news:g8b4ng$a05$1@aioe.org... [...] > The latter is necessary to make changes to either the smart pointer itself > or the object pointed to in case raw pointer are used. We can see my > personnal implementation here and I would like to propose the following > function signatures: > > template <typename T> > class shifted_allocator > { > public: > typedef shifted<T> value_type; > typedef shifted_ptr<T> pointer; > typedef shifted_ptr<const T> const_pointer; > > value_type * allocate(size_type s, const void * = 0); > void deallocate(pointer & p, size_type); > void construct(value_type * p, const T & x); > void destroy(pointer & p); > ... > }; [...] Moreover it turns out this will become an even bigger problem if the new rule of virtualizing allocator is accepted because the parameters will be totaly different: namespace std { class allocator_implementation { typedef void * pointer; virtual void deallocate(pointer p, size_type) = 0; ... }; } template <typename T> class shifted_allocator : std::allocator_implementation { public: typedef shifted<T> value_type; typedef shifted_ptr<T> pointer; typedef shifted_ptr<const T> const_pointer; virtual void deallocate(pointer & p, size_type) // won't override { } ... }; I think the idea of virtualizing the allocators should not be accepted because it will be irreversible. Correct me if I'm wrong but I don't see why we couldn't virtualize containers instead. Everybody thinks this means slower performance but most of today's compilers are smart enough to bypass the virtual tables. Let's consider the following: template <typename T> class list_base : public ...{ /* common operations */ ... }; template <typename T, typename Alloc> class list : public list_base<T> { ... }; -Phil -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Re: [allocator.concept] smart pointer clarifications
"Phil Bouchard" <phil@fornux.com> wrote in message news:g8glbh$fd6$1@aioe.org... [...] > template <typename T> > class list_base : public ...{ /* common operations */ ... }; > > template <typename T, typename Alloc> > class list : public list_base<T> { ... }; Where: template <typename T> virtual allocator_type list_base<T>::get_allocator() const = 0; And, for example: template <typename T, typename Alloc> virtual allocator_type list<T, Alloc>::get_allocator() const { return allocator_type(*static_cast<const _Node_Alloc_type*>(&this->_M_impl)); } -Phil -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Re: [allocator.concept] smart pointer clarifications
"Phil Bouchard" <phil@fornux.com> wrote in message news:g8jofb$ust$1@aioe.org... [...] > Where: > template <typename T> > virtual allocator_type list_base<T>::get_allocator() const = 0; > > And, for example: > template <typename T, typename Alloc> > virtual allocator_type list<T, Alloc>::get_allocator() const > { > return allocator_type(*static_cast<const > _Node_Alloc_type*>(&this->_M_impl)); > } Sorry here I meant protected functions should be virtual, not get_allocator(): template <typename T> class list_base : public ... { virtual _List_node<_Tp>* _M_get_node() = 0; virtual void _M_put_node(_List_node<_Tp>* __p) = 0; }; template <typename T, typename Alloc> class list : public list_base<T> { protected: _List_impl _M_impl; virtual _List_node<_Tp>* _M_get_node() { return _M_impl._Node_Alloc_type::allocate(1); } virtual void _M_put_node(_List_node<_Tp>* __p) { _M_impl._Node_Alloc_type::deallocate(__p, 1); } public: _Alloc get_allocator() const { return _Alloc(*static_cast<const _Node_Alloc_type*>(&this->_M_impl)); } ... }; -Phil -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
![]() |
|
| Thread Tools | Search this Thread |
| Display Modes | |
|
|