From: Phil Bouchard on
Greetings,

I am wondering what would be the best way to instanciate an STL container
with a special allocator but using a smart pointer to access the nodes.
Apart from this the allocator will generate dictinct pointee type named
"smart<>". For example:

template <typename T>
smart
{ T e_; ...};

template <typename T>
smart_ptr
{
T * p_;
...
smart_ptr(smart<T> *) {...}
};

template <typename T>
smart_allocator
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef smart <T> * pointer;
typedef const smart <T> * const_pointer;
typedef smart <T> & reference;
typedef const smart <T> & const_reference;
typedef smart <T> value_type;
...
};

int main()
{
std::vector < int, smart_allocator<int> > cInt;
}


Now I would like all nodes allocated by smart_allocator to be referenced by
a smart_ptr but I think this is not possible because raw pointers is hard
coded into STL which is very strange. I therefore don't use them, just
pointers to smart<> (smart<> *) but when I attempt to compile such code I
run into problems compiling "__normal_iterator". But I am wondering why is
that class related to my allocator at all? I would like some enlightenment
regarding this:

....stl_vector.h: In member function `__gnu_cxx::__normal_iterator<typename
_Alloc::const_pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp,
_Alloc>::begin() const [with _Tp = int, _Alloc = smart_allocator<int>]':
....stl_vector.h:221: instantiated from `std::vector<_Tp,
_Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = int, _Alloc =
smart_allocator<int>]'
shifted_ptr_test2.cpp:66: instantiated from here
....stl_vector.h:322: error: no matching function for call to
`__gnu_cxx::__normal_iterator<const smart<int>*, std::vector<int,
smart_allocator<int> > >::__normal_iterator(int* const&)'
....stl_iterator.h:587: note: candidates are:
__gnu_cxx::__normal_iterator<const smart<int>*, std::vector<int,
smart_allocator<int> > >::__normal_iterator(const
__gnu_cxx::__normal_iterator<const smart<int>*, std::vector<int,
smart_allocator<int> > >&)
....stl_iterator.h:603: note:
__gnu_cxx::__normal_iterator<_Iterator,_Container>::__normal_iterator(const
_Iterator&) [with _Iterator = const smart<int>*, _Container =
std::vector<int, smart_allocator<int> >]
....stl_iterator.h:600: note:
__gnu_cxx::__normal_iterator<_Iterator,_Container>::__normal_iterator()
[with _Iterator = const smart<int>*, _Container = std::vector<int,
smart_allocator<int> >]


Regards,
-Phil


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

From: Kai-Uwe Bux on
Phil Bouchard wrote:

> Greetings,
>
> I am wondering what would be the best way to instanciate an STL container
> with a special allocator but using a smart pointer to access the nodes.
> Apart from this the allocator will generate dictinct pointee type named
> "smart<>". For example:
>
> template <typename T>
> smart
> { T e_; ...};
>
> template <typename T>
> smart_ptr
> {
> T * p_;
> ...
> smart_ptr(smart<T> *) {...}
> };
>
> template <typename T>
> smart_allocator
> {
> typedef size_t size_type;
> typedef ptrdiff_t difference_type;
> typedef smart <T> * pointer;
> typedef const smart <T> * const_pointer;
> typedef smart <T> & reference;
> typedef const smart <T> & const_reference;
> typedef smart <T> value_type;
> ...
> };

Your allocator violates [20.1.5/4]

Implementations of containers described in this International Standard are
permitted to assume that their Allocator template parameter meets the
following two additional requirements beyond those in Table 32.
[...]
? The typedef members pointer, const_pointer, size_type, and
difference_type are required to be T*,T const*, size_t, and ptrdiff_t,
respectively.


> int main()
> {
> std::vector < int, smart_allocator<int> > cInt;
> }

Aha:

int & != smart_allocator<int>::reference == smart<int> &

Maybe,

std::vector< smart<T>, smart_allocator<T> >

would work.


[snip]


Best

Kai-Uwe Bux



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

From: Phil Bouchard on

"Kai-Uwe Bux" <jkherciueh(a)gmx.net> wrote in message
news:g3hk32$hr4$1(a)aioe.org...

[...]

> Your allocator violates [20.1.5/4]
>
> Implementations of containers described in this International Standard
> are
> permitted to assume that their Allocator template parameter meets the
> following two additional requirements beyond those in Table 32.
> [...]
> ? The typedef members pointer, const_pointer, size_type, and
> difference_type are required to be T*,T const*, size_t, and ptrdiff_t,
> respectively.

How unfortunate! It wouldn't make sense having to explicitly define these
typedefs inside the allocator in the first place because they can't even be
changed.

>> int main()
>> {
>> std::vector < int, smart_allocator<int> > cInt;
>> }
>
> Aha:
>
> int & != smart_allocator<int>::reference == smart<int> &
>
> Maybe,
>
> std::vector< smart<T>, smart_allocator<T> >
>
> would work.

Thanks but I tried it and I was still stuck into __normal_iterator not
having the right constructor:

....stl_vector.h: In member function `__gnu_cxx::__normal_iterator<typename
_Alloc::const_pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp,
_Alloc>::begin() const [with _Tp = smart_ptr<vector>, _Alloc =
smart_allocator<vector>]':
....stl_vector.h:221: instantiated from `std::vector<_Tp,
_Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp =
smart_ptr<vector>, _Alloc = smart_allocator<vector>]'
shifted_ptr_test2.cpp:66: instantiated from here
....stl_vector.h:322: error: no matching function for call to
`__gnu_cxx::__normal_iterator<const smart<vector>*,
std::vector<smart_ptr<vector>, smart_allocator<vector> >
>::__normal_iterator(smart_ptr<vector>* const&)'
....stl_iterator.h:587: note: candidates are:
__gnu_cxx::__normal_iterator<const smart<vector>*,
std::vector<smart_ptr<vector>, smart_allocator<vector> >
>::__normal_iterator(const __gnu_cxx::__normal_iterator<const
smart<vector>*, std::vector<smart_ptr<vector>, smart_allocator<vector> > >&)
....stl_iterator.h:603: note:
__gnu_cxx::__normal_iterator<_Iterator, _Container>::__normal_iterator(const
_Iterator&) [with _Iterator = const smart<vector>*, _Container =
std::vector<smart_ptr<vector>, smart_allocator<vector> >]
....stl_iterator.h:600: note:
__gnu_cxx::__normal_iterator<_Iterator, _Container>::__normal_iterator()
[with _Iterator = const smart<vector>*, _Container =
std::vector<smart_ptr<vector>, smart_allocator<vector> >]

I can always copy & paste my own STL as seen what happens.


Regards,
-Phil



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

From: Kai-Uwe Bux on
Phil Bouchard wrote:

>
> "Kai-Uwe Bux" <jkherciueh(a)gmx.net> wrote in message
> news:g3hk32$hr4$1(a)aioe.org...
>
> [...]
>
>> Your allocator violates [20.1.5/4]
>>
>> Implementations of containers described in this International Standard
>> are
>> permitted to assume that their Allocator template parameter meets the
>> following two additional requirements beyond those in Table 32.
>> [...]
>> ? The typedef members pointer, const_pointer, size_type, and
>> difference_type are required to be T*,T const*, size_t, and
>> ptrdiff_t, respectively.
>
> How unfortunate! It wouldn't make sense having to explicitly define these
> typedefs inside the allocator in the first place because they can't even
> be changed.

True.

The standard leaves this as a quality of implementation issue. An STL
implementation is definitely allowed to support more general allocators.


>>> int main()
>>> {
>>> std::vector < int, smart_allocator<int> > cInt;
>>> }
>>
>> Aha:
>>
>> int & != smart_allocator<int>::reference == smart<int> &
>>
>> Maybe,
>>
>> std::vector< smart<T>, smart_allocator<T> >
>>
>> would work.
>
> Thanks but I tried it and I was still stuck into __normal_iterator not
> having the right constructor:
[snip error messages]

Well, gcc uses some nasty tricks. Somewhere in the definition of
std::vector<T,A> it does something like this:

typedef typename A::template rebind<T>::other true_allocator_type;

and then it uses the true_allocator_type for certain things. I suspect that
this is the reason, it wouldn't get fooled by using

std::vector< smart<T>, smart_allocator<T> >

(I am actually not entirely sure whether this behavior is standard
compliant; but I think it is ok: containers such as list and map have to
rebind the allocator internally anyway.)


I guess, you could finally try

std::vector< smart<T>, smart_allocator< smart<T> > >

where smart_allocator<> would need to be rewritten so that it will strip
smart<T> down to T internally.



Best

Kai-Uwe Bux

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