Custom Allocators question

G

Guest

Hi All,

I'm not sure if I'm dealing with a C++ question or a compiler question,
so please forgive me if I'm asking in the wrong spot. If so, maybe
someone can direct me to more appropriate spot.

In migrating from gcc 3.2.3 to gcc 3.4.3 the following situation comes
up.

I have the following:
//typedef std::vector<TestClass* > TestClassVector;
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;

TestClassVector a;
TestClassVector * tmpVecPtr = &a;
TestClass * tmpPtr = new TestClass(5);
a.push_back(tmpPtr);

if ( (*tmpVecPtr)[0] != NULL )
cout<<"hello main"<<endl;

When using the custom allocator this line breaks:
(*tmpVecPtr)[0] != NULL )

thinking that this field is a TestClass and opposed to the TestClass*
which it should be. If I use the first typedef(with no allocator
specified) it compiles fine with gcc 3.4.3. Also both compile fine
under gcc 3.2.3

I'm not clear if there has been a tightening compliance of the compiler
and i need to add a method to the allocator class to make this compile,
or what exactly my problem is.

If anyone can shed some light on this I would be very appreciative.

Thanks much!


I'll attach the complete code below:

#include <iostream>
#include <vector>

using namespace std;

#ifndef MEMORY_H
#include <memory>
#define MEMORY_H
#endif


template <class T>
class TestAllocator;

template <>
class TestAllocator<void>
{
public:
typedef void* pointer;
typedef const void* const_pointer;

typedef void value_type;

template <class U>
struct rebind
{
typedef TestAllocator<U> other;
};
};

template <class T>
class TestAllocator
{
public:
// Type definitions
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;

typedef T& reference;
typedef const T& const_reference;

pointer address(reference value) const { return &value; }

const_pointer address(const_reference value) const { return &value;
}

// Constructors and destructor
TestAllocator() throw() {}

TestAllocator(const TestAllocator& copy) {}

template <class U>
TestAllocator(const TestAllocator<U>&) throw() {}

~TestAllocator() throw() {}

// Assignment Operator
TestAllocator& operator=(const TestAllocator& rhs) { return *this;
}

inline pointer
allocate(size_type n, const_pointer = 0)
{
pointer p;
size_type size;

size = n * sizeof(T);

p = (pointer) ::eek:perator new(size);

return p;
}
inline void
deallocate(pointer p, size_type n = 1)
{
::eek:perator delete(p);
}

void
construct(pointer p, const T& val)
{
new((void*) p) T(val);
}

void
destroy(pointer p)
{
((T*) p)->~T();
}

size_type
max_size() const throw()
{
return std::numeric_limits<std::size_t>::max() / sizeof(T);
}

template <class U>
struct rebind
{
typedef TestAllocator<U> other;
};
};

class TestClass
{
public:

TestClass(int a): b(a){};
~TestClass();
int getNum() { return b;};

int b;
};

//typedef std::vector<TestClass* > TestClassVector;
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;


int main(int argc, char *argv[])
{
TestClassVector a;
TestClassVector * tmpVecPtr = &a;
TestClass * tmpPtr = new TestClass(5);
a.push_back(tmpPtr);

if ( (*tmpVecPtr)[0] != NULL )
cout<<"hello main"<<endl;
}
 
G

Guest

Ahh.. details!... :)

Switching between the vector definition either w/ or without the
Allocator specified causes it to not match the != NULL. in the case
where an Allocator is specified.

Thanks..

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0l'
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':
 
P

Panjandrum

Switching between the vector definition either w/ or without the
Allocator specified causes it to not match the != NULL. in the case
where an Allocator is specified.

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0l'

!= 0l' ??? What's that?

/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:

x86_64? 64Bit?
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':
TestClass * tmpPtr = new TestClass(5);

Highly questionable. 'new' throws an exception (and doesn't return
NULL) in case of OOM (out-of-memory) according to the C++ Standard (not
actually e.g. in Linux). Anyway ...
if ((*tmpVecPtr)[0] != NULL )

Try:
if ((*tmpVecPtr)[0] != (TestClass*) 0)

Re-think your design!
 
G

Guest

Panjandrum said:
Switching between the vector definition either w/ or without the
Allocator specified causes it to not match the != NULL. in the case
where an Allocator is specified.

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0l'

!= 0l' ??? What's that?
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:

x86_64? 64Bit?
yep
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':
TestClass * tmpPtr = new TestClass(5);

Highly questionable. 'new' throws an exception (and doesn't return
NULL) in case of OOM (out-of-memory) according to the C++ Standard (not
actually e.g. in Linux). Anyway ...
if ((*tmpVecPtr)[0] != NULL )

Try:
if ((*tmpVecPtr)[0] != (TestClass*) 0)

This now spits out:

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0u'
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
const _Tp&) [with _Tp = said:
Re-think your design!

This is just a sample code broken out from the real code that
reproduces the problem in the real code base.

Any other suggestions? Is there something i'm needing to specify in
the allocator that's not there??

Thanks much for the time.
 
P

Panjandrum

Panjandrum said:
Try:
if ((*tmpVecPtr)[0] != (TestClass*) 0)

This now spits out:

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0u'

My last attempt (BTW, I hate STL):

if ((*tmpVecPtr)[(TestClassVector::size_type) 0] != (TestClass*) 0)
 
G

Guest

Panjandrum said:
Panjandrum said:
Try:
if ((*tmpVecPtr)[0] != (TestClass*) 0)

This now spits out:

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0u'

My last attempt (BTW, I hate STL):

if ((*tmpVecPtr)[(TestClassVector::size_type) 0] != (TestClass*) 0)

Hmm.no luck either. Many thanks for the suggestions.

I don't think it's along the lines of a cast issue. What's got me
perplexed is why the presence of the custom allocator in the vector
definition causes the compiler to not recognize the operator!=, where
if you take this out, it compiles fine.

Anyone else have any insight/suggestions, i need to get past this
error!

Thanks!
 
A

Artie Gold

Panjandrum said:
Panjandrum wrote:
Try:
if ((*tmpVecPtr)[0] != (TestClass*) 0)
This now spits out:

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0u'
My last attempt (BTW, I hate STL):

if ((*tmpVecPtr)[(TestClassVector::size_type) 0] != (TestClass*) 0)

Hmm.no luck either. Many thanks for the suggestions.

I don't think it's along the lines of a cast issue. What's got me
perplexed is why the presence of the custom allocator in the vector
definition causes the compiler to not recognize the operator!=, where
if you take this out, it compiles fine.

Anyone else have any insight/suggestions, i need to get past this
error!

Thanks!
I've been looking at your problem -- and although I have not yet found a
solution, I do have a suggestion: Look much deeper into the chain of
errors generated -- I think your problem is down the list somewhere.

HTH,
--ag
 
T

Thomas Tutone

(e-mail address removed) wrote:

[snip]
I have the following:
//typedef std::vector<TestClass* > TestClassVector;
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;

Forgive me if I'm missing the point, and I'm far from an expert on
allocators, but one would more commonly expect to see the type of the
allocator template specialization match the value_type contained in the
vector. Here, in contrast, you have TestClass* as the value_type of
the vector, but TestClass (i.e., not a pointer) as the type of the
allocator template specialization. In other words, I would have
expected your typedef to read:

typedef std::vector<TestClass*, TestAllocator<TestClass*> >
TestClassVector

or

typedef std::vector<TestClass, TestAllocation<TestClass> >
TestClassVector

but your example seems to meld the two, which looks very strange to me.

But as I said, maybe I've just missed the point.

Best regards,

Tom
 
J

Jonathan Mcdougall

//typedef std::vector said:
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;

int main(int argc, char *argv[])
{
TestClassVector a;
TestClassVector * tmpVecPtr = &a;
TestClass * tmpPtr = new TestClass(5);
a.push_back(tmpPtr);

if ( (*tmpVecPtr)[0] != NULL )
cout<<"hello main"<<endl;
}
test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0l'

Looks like operator[] is not returning a TestClass*. Can you try
determining what type it returns? Try something like

TestClass * c = (*tmpVecPtr)[0];

It should tell you something like "cannot convert X to TestClass*".
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':

What's the rest of the message? Are there other errors?

The code compiles fine on Comeau. Looks like your compiler is broken.


Jonathan
 
G

Guest

Jonathan said:
//typedef std::vector<TestClass* > TestClassVector;
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;

int main(int argc, char *argv[])
{
TestClassVector a;
TestClassVector * tmpVecPtr = &a;
TestClass * tmpPtr = new TestClass(5);
a.push_back(tmpPtr);

if ( (*tmpVecPtr)[0] != NULL )
cout<<"hello main"<<endl;
}
test.cpp: In function `int main(int, char**)':
test.cpp:128: error: no match for 'operator!=' in
'tmpVecPtr->std::vector<_Tp, _Alloc>::eek:perator[] [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>](0ul) != 0l'

Looks like operator[] is not returning a TestClass*. Can you try
determining what type it returns? Try something like

TestClass * c = (*tmpVecPtr)[0];

It should tell you something like "cannot convert X to TestClass*".

Jonathen,

i like that idea...

that line will cause this:

test.cpp: In function `int main(int, char**)':
test.cpp:128: error: cannot convert `TestClass' to `TestClass*' in
initialization
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':
/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/stl_vector.h:564:
instantiated from `void std::vector<_Tp, _Alloc>::push_back(const
_Tp&) [with _Tp = TestClass*, _Alloc = TestAllocator<TestClass>]'
test.cpp:126: instantiated from here

/usr/lib/gcc/x86_64-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/vector.tcc:
In member function `void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename
_Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
TestClass*, _Alloc = TestAllocator<TestClass>]':

What's the rest of the message? Are there other errors?

Yea there are about 1000 more lines of the stl nonsense that spits out
after that.
For some reason, soon as that allocator is specified, it thinks that
element is the TestClass, not the pointer.
The code compiles fine on Comeau. Looks like your compiler is broken.

Hmmm... I'm wondering if it's a gcc bug possibly? This DOES
compile(with the allocator) w/ gcc 3.2.3...it breaks w/ the 3.4.3

Thanks much for taking the time to compile that! ideas?

Nate
 
G

Guest

Thomas said:
(e-mail address removed) wrote:

[snip]
I have the following:
//typedef std::vector<TestClass* > TestClassVector;
typedef std::vector<TestClass*,TestAllocator<TestClass> >
TestClassVector;

Forgive me if I'm missing the point, and I'm far from an expert on
allocators, but one would more commonly expect to see the type of the
allocator template specialization match the value_type contained in the
vector. Here, in contrast, you have TestClass* as the value_type of
the vector, but TestClass (i.e., not a pointer) as the type of the
allocator template specialization. In other words, I would have
expected your typedef to read:

typedef std::vector<TestClass*, TestAllocator<TestClass*> >
TestClassVector

or

typedef std::vector<TestClass, TestAllocation<TestClass> >
TestClassVector

but your example seems to meld the two, which looks very strange to me.

But as I said, maybe I've just missed the point.
Tom

I knew nothing of allocators until i hit this compile problem. My
lightweight understanding of them after my initial investigation, i
came to same conclusion. I'm simply trying to get the codebase to
recompile and wasn't original auther. (this is just a stripped down
sample to post) Seeing as though it did compile(and the work
functionally) with the earlier compiler, my initial assumption was that
perhaps this version was more compliant and i'm just missing something
that needs to be added to allocator. But the returning of different
types strikes me as somewhat more extreme/possible bug?

Maybe i need to dig more into the guts of the real code and see if
there is a design flaw as well.

Thanks for the time!
 
J

Jonathan Mcdougall

I have the following:
Forgive me if I'm missing the point, and I'm far from an expert on
allocators,

Perhaps, but you have got keen eyes.
but one would more commonly expect to see the type of the
allocator template specialization match the value_type contained in the
vector. Here, in contrast, you have TestClass* as the value_type of
the vector, but TestClass (i.e., not a pointer) as the type of the
allocator template specialization. In other words, I would have
expected your typedef to read:

typedef std::vector<TestClass*, TestAllocator<TestClass*> >
TestClassVector

or

typedef std::vector<TestClass, TestAllocation<TestClass> >
TestClassVector

but your example seems to meld the two, which looks very strange to me.

To the OP:
operator[] returns a reference, a typedef which comes from the
allocator. Since you passed a TestClass, the reference was defined as
'TestClass&'. You are trying to convert a 'TestClass&' into a
'TestClass*' which is illegal. Your typedef should be

typedef std::vector<TestClass*,TestAllocator<TestClass*> >;


Jonathan
 
G

Guest

For grins i actually did match those types up to:
typedef std::vector<TestClass*, TestAllocator<TestClass*> >
TestClassVector

(knowing full well it functionally breaks the real code) and it does
compile now!

SO.... i'm still curious as to why this changed from gcc versions and
if i'm dealing with a C++ or compiler issue ( bug/compliance)

Can anyone that has more experience comment on this, should this not
actually be allowed (mixing the Type vs. the pointer -to)
Thanks
 
G

Guest

AH.

Ok, thanks for all the insight guys. i appreciate it.

Wonder why this worked(maybe in fact it wasn't) with the previous gcc
version. i'll have to explore this more

Thanks for the time.
 
E

Earl Purple

Maybe you need to know what vector does. It uses placement new - this
allows it to allocate more space than is needed for its objects without
having to call their constructors (thus reserve(). Even when you don't
call reserve explicitly, it will often reserve when growing).

It gives you the option of the allocator parameter to reduce coupling -
separating the functionality of vector (manipulating multiple objects)
with that of the allocation of memory.

When vector makes a call to its allocator, it wants an address to the
start of memory space to hold N objects. Therefore if its type is T it
wants a T* pointer. So if its type is T* it wants a T** pointer.

C++ is typesafe, so it won't allow you to implicitly convert between T*
and T**. (You need a reinterpret_cast,which is generally a bad idea).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top