Vector Of auto ptr of class help (Please!)

R

reb

I more or less inherited some code that makes liberal use of STL, among
other things. Up to now I've sort of considered templates a kind of
black art, but I'm coming around to see how they can be useful. I'd
really like them if I could figure out this one problem. I'm porting
this code from Mac CodeWarrior to XCode which is using GCC 4.0.
CodeWarrior apparently rolled their own version of STL, where the
vector class contents are quite different than the gnu version.

I'll make this as abbreviated as possible. We have a record (actually,
many records, but this is just an example) like:

class CHelpMe : public CRefCnt
{
// usual ctors, dtor, methods. Nothing fancy here;
};

Base class CRefCnt does what it implies:

class CRefCnt
{
public:
virtual int AddRef() { return IncrementRefCnt(); }
virtual int Release() { return DecrementRefCnt();}

virtual ~CR180XmlDbRefCnt() { assert( 0 == m_iRefCnt );}
protected:
CR180XmlDbRefCnt() : m_iRefCnt( 1) {;}
virtual int IncrementRefCnt() { return ++m_iRefCnt;}
virtual int DecrementRefCnt() { int cRefs= --m_iRefCnt; if( cRefs ==
0) delete this; return cRefs;};
private:
int m_iRefCnt;

};

We also have an auto ptr class (condensed somewhat for posting):

template <class T>
class CAutoPtr
{
public:
CAutoPtr() : p( NULL) {;};
CAutoPtr(T* lp, bool bIsStrongRef= false) { if ((((p = lp) != NULL))
&& ! bIsStrongRef) p->AddRef();}
CAutoPtr(const CAutoPtr<T>& lp) { if ((p = lp.p) != NULL) p->AddRef();
}
~CAutoPtr() { if (p) p->Release(); p= NULL;}

void Release() { if( NULL == p) return; p->Release();p = NULL; }

_NoAddRefReleaseOnCAutoPtr<T>* operator->() const { return
(_NoAddRefReleaseOnCAutoPtr<T>*)p;}

operator T*() const { return p; }
T& operator*() const { assert( NULL != p ); return *p;}
T** operator&() { assert (NULL == p); return &p;}
T* operator=(T* lp) { if( p == lp) return p; if( p) p->Release(); p=
lp; if(p) p->AddRef(); return p;}
const CAutoPtr<T>& operator=(const CAutoPtr<T>& rhs) { if( p == rhs.p)
return *this; if( p) p->Release(); p= rhs.p; if( p) p->AddRef(); return
*this;}
bool operator==(T* pT) const { return p == pT;}
void Attach(T* p2) { if (p) p->Release(); p = p2; }
T* Detach() { T* pt = p; p = NULL;return pt;}

T* p;
};

Finally, we have a couple of typedefs:

typedef CAutoPtr<CHelpMe> CHelpMePtr;
typedef std::vector<CHelpMePtr> CHelpMePtrVector;

The problem comes when compiling when we get this error on the vector
typedef line:
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:174:
error: no matching function for call to
'std::allocator<CHelpMePtr>::destroy(CHelpMe**)'
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h:107:
note: candidates are: void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*)
[with _Tp = CHelpMePtr]

My limited knowledge of STL sees this as the compiler thinking that
CAutoPtr of CHelpMe is too ambiguous for the standard allocator class.
I've tried any number of ways to resolve this, without complete
success. Note that this same code compiles and runs fine under VC++
6.0.

Any ideas? Thanks!
 
M

mlimber

I more or less inherited some code that makes liberal use of STL, among
other things. Up to now I've sort of considered templates a kind of
black art, but I'm coming around to see how they can be useful. I'd
really like them if I could figure out this one problem. I'm porting
this code from Mac CodeWarrior to XCode which is using GCC 4.0.
CodeWarrior apparently rolled their own version of STL, where the
vector class contents are quite different than the gnu version.

I'll make this as abbreviated as possible. We have a record (actually,
many records, but this is just an example) like:

class CHelpMe : public CRefCnt
{
// usual ctors, dtor, methods. Nothing fancy here;
};

Base class CRefCnt does what it implies:

class CRefCnt
{
public:
virtual int AddRef() { return IncrementRefCnt(); }
virtual int Release() { return DecrementRefCnt();}

virtual ~CR180XmlDbRefCnt() { assert( 0 == m_iRefCnt );}
protected:
CR180XmlDbRefCnt() : m_iRefCnt( 1) {;}
virtual int IncrementRefCnt() { return ++m_iRefCnt;}
virtual int DecrementRefCnt() { int cRefs= --m_iRefCnt; if( cRefs ==
0) delete this; return cRefs;};
private:
int m_iRefCnt;

};

We also have an auto ptr class (condensed somewhat for posting):

template <class T>
class CAutoPtr
{
public:
CAutoPtr() : p( NULL) {;};
CAutoPtr(T* lp, bool bIsStrongRef= false) { if ((((p = lp) != NULL))
&& ! bIsStrongRef) p->AddRef();}
CAutoPtr(const CAutoPtr<T>& lp) { if ((p = lp.p) != NULL) p->AddRef();
}
~CAutoPtr() { if (p) p->Release(); p= NULL;}

void Release() { if( NULL == p) return; p->Release();p = NULL; }

_NoAddRefReleaseOnCAutoPtr<T>* operator->() const { return
(_NoAddRefReleaseOnCAutoPtr<T>*)p;}

operator T*() const { return p; }
T& operator*() const { assert( NULL != p ); return *p;}
T** operator&() { assert (NULL == p); return &p;}
T* operator=(T* lp) { if( p == lp) return p; if( p) p->Release(); p=
lp; if(p) p->AddRef(); return p;}
const CAutoPtr<T>& operator=(const CAutoPtr<T>& rhs) { if( p == rhs.p)
return *this; if( p) p->Release(); p= rhs.p; if( p) p->AddRef(); return
*this;}
bool operator==(T* pT) const { return p == pT;}
void Attach(T* p2) { if (p) p->Release(); p = p2; }
T* Detach() { T* pt = p; p = NULL;return pt;}

T* p;
};

Finally, we have a couple of typedefs:

typedef CAutoPtr<CHelpMe> CHelpMePtr;
typedef std::vector<CHelpMePtr> CHelpMePtrVector;

The problem comes when compiling when we get this error on the vector
typedef line:
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:174:
error: no matching function for call to
'std::allocator<CHelpMePtr>::destroy(CHelpMe**)'
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h:107:
note: candidates are: void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*)
[with _Tp = CHelpMePtr]

My limited knowledge of STL sees this as the compiler thinking that
CAutoPtr of CHelpMe is too ambiguous for the standard allocator class.
I've tried any number of ways to resolve this, without complete
success. Note that this same code compiles and runs fine under VC++
6.0.

Any ideas? Thanks!

I tried this code:

#include <vector>
#include <cassert>

class CRefCnt
{
public:
virtual int AddRef() { return IncrementRefCnt(); }
virtual int Release() { return DecrementRefCnt();}
virtual ~CRefCnt() { assert( 0 == m_iRefCnt );}
protected:
CRefCnt() : m_iRefCnt( 1) {;}
virtual int IncrementRefCnt() { return ++m_iRefCnt;}
virtual int DecrementRefCnt() { int cRefs= --m_iRefCnt; if(
cRefs == 0) delete this; return cRefs;};
private:
int m_iRefCnt;
};

template <class T>
class CAutoPtr
{
public:
CAutoPtr() : p( NULL) {;};
CAutoPtr(T* lp, bool bIsStrongRef= false) { if ((((p = lp) !=
NULL)) && ! bIsStrongRef) p->AddRef();}
CAutoPtr(const CAutoPtr<T>& lp) { if ((p = lp.p) != NULL)
p->AddRef(); }
~CAutoPtr() { if (p) p->Release(); p= NULL;}
void Release() { if( NULL == p) return; p->Release();p = NULL;
}
//_NoAddRefReleaseOnCAutoPtr<T>* operator->() const { return
(_NoAddRefReleaseOnCAutoPtr<T>*)p;}
operator T*() const { return p; }
T& operator*() const { assert( NULL != p ); return *p;}
T** operator&() { assert (NULL == p); return &p;}
T* operator=(T* lp) { if( p == lp) return p; if( p)
p->Release(); p=lp; if(p) p->AddRef(); return p;}
const CAutoPtr<T>& operator=(const CAutoPtr<T>& rhs) { if( p ==
rhs.p) return *this; if( p) p->Release(); p= rhs.p; if( p) p->AddRef();
return *this;}
bool operator==(T* pT) const { return p == pT;}
void Attach(T* p2) { if (p) p->Release(); p = p2; }
T* Detach() { T* pt = p; p = NULL;return pt;}
T* p;
};

class CHelpMe : public CRefCnt {};

typedef CAutoPtr<CHelpMe> CHelpMePtr;
typedef std::vector<CHelpMePtr> CHelpMePtrVector;

int main()
{
CHelpMePtrVector v( 10 );
return 0;
}

with g++ 3.4.1, VC++ 6 (sp6 and all STL patches applied from
dinkumware.com), Comeau online
(http://www.comeaucomputing.com/tryitout/), and dinkumware online
(using EDG and Microsoft .NET 2003). All compiled it fine. Note that I
had to make some additional changes to your code, and in particular I
deleted the -> operator in CAutoPtr because I don't have the
_NoAddRefReleaseOnCAutoPtr<> class.

Can you post a minimal but complete sample that demonstrates the
problem?

Cheers! --M
 
R

reb

Thanks for checking that out. I also took your code, changed it
slightly and built it as a separate project. It appears to be a gcc 4.0
vs. gcc 3.x thing. I could compile successfully under 3.3.
Unfortuately, I need to use 4.0 (required to get it to run on Intel
Macs). Here's the current version:

#include <vector>
#include <cassert>

template <class T>
class _NoAddRefReleaseOnCAutoPtr : public T
{
private:
virtual int AddRef()=0;
virtual int Release()=0;
};

class CRefCnt
{
public:
virtual int AddRef() { return IncrementRefCnt();}
virtual int Release() { return DecrementRefCnt();}
virtual ~CRefCnt() { assert( 0 == m_iRefCnt );}
protected:
CRefCnt() : m_iRefCnt( 1) {;}
virtual int IncrementRefCnt() { return ++m_iRefCnt;}
virtual int DecrementRefCnt() { int cRefs= --m_iRefCnt;
if(cRefs == 0) delete this; return cRefs;};
private:
int m_iRefCnt;

};

template <class T>
class CAutoPtr
{
public:
CAutoPtr() : p( NULL) {;};
CAutoPtr(T* lp, bool bIsStrongRef= false) { if ((((p = lp) !=
NULL)) && ! bIsStrongRef) p->AddRef();}
CAutoPtr(const CAutoPtr<T>& lp) { if ((p = lp.p) != NULL)
p->AddRef(); }
~CAutoPtr() { if (p) p->Release(); p= NULL;}

void Release() { if( NULL == p) return; p->Release();p = NULL;
}

_NoAddRefReleaseOnCAutoPtr<T>* operator->() const { return
(_NoAddRefReleaseOnCAutoPtr<T>*)p;}
operator T*() const { return p; }
T& operator*() const { assert( NULL != p ); return *p;}
T** operator&() { assert (NULL == p); return &p;}
T* operator=(T* lp) { if( p == lp) return p; if( p)
p->Release(); p=lp; if(p) p->AddRef(); return p;}
const CAutoPtr<T>& operator=(const CAutoPtr<T>& rhs) { if( p ==
rhs.p) return *this; if( p) p->Release(); p= rhs.p; if( p) p->AddRef();
return *this;}
bool operator==(T* pT) const { return p == pT;}

void Attach(T* p2) { if (p) p->Release(); p = p2; }
T* Detach() { T* pt = p; p = NULL;return pt;}
T* p;
};

class CHelpMe : public CRefCnt {};

typedef CAutoPtr<CHelpMe> CHelpMePtr;
typedef std::vector<CHelpMePtr> CHelpMePtrVector;

int main()
{
CHelpMePtrVector v( 10 );
return 0;
}


And here's the compiler output:

/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:
In function 'void std::_Destroy(_ForwardIterator, _ForwardIterator,
_Allocator) [with _ForwardIterator = CHelpMePtr*, _Allocator =
std::allocator<CHelpMePtr>]':
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_vector.h:273:
instantiated from 'std::vector<_Tp, _Alloc>::~vector() [with _Tp =
CHelpMePtr, _Alloc = std::allocator<CHelpMePtr>]'
/Users/reb/test1/main.cpp:71: instantiated from here
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:174:
error: no matching function for call to
'std::allocator<CHelpMePtr>::destroy(CHelpMe**)'
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h:107:
note: candidates are: void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*)
[with _Tp = CHelpMePtr]

In playing with the code some more, if I comment the CAutoPtr
operator&, I still get a compiler error, but it's quite different:

/usr/bin/ld:
/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/libgcc_eh.a(unwind-dw2.o)
has external relocation entries in non-writable section (__TEXT,__text)
for symbols:
restFP
saveFP
collect2: ld returned 1 exit status

Any idea what might be ticking off the 4.0 compiler? If not, any
suggestions for where I might find an answer? Thanks again. -R
 
M

mlimber

Thanks for checking that out. I also took your code, changed it
slightly and built it as a separate project. It appears to be a gcc 4.0
vs. gcc 3.x thing. I could compile successfully under 3.3.
Unfortuately, I need to use 4.0 (required to get it to run on Intel
Macs). Here's the current version:

#include <vector>
#include <cassert>

template <class T>
class _NoAddRefReleaseOnCAutoPtr : public T
{
private:
virtual int AddRef()=0;
virtual int Release()=0;
};

class CRefCnt
{
public:
virtual int AddRef() { return IncrementRefCnt();}
virtual int Release() { return DecrementRefCnt();}
virtual ~CRefCnt() { assert( 0 == m_iRefCnt );}
protected:
CRefCnt() : m_iRefCnt( 1) {;}
virtual int IncrementRefCnt() { return ++m_iRefCnt;}
virtual int DecrementRefCnt() { int cRefs= --m_iRefCnt;
if(cRefs == 0) delete this; return cRefs;};
private:
int m_iRefCnt;

};

template <class T>
class CAutoPtr
{
public:
CAutoPtr() : p( NULL) {;};
CAutoPtr(T* lp, bool bIsStrongRef= false) { if ((((p = lp) !=
NULL)) && ! bIsStrongRef) p->AddRef();}
CAutoPtr(const CAutoPtr<T>& lp) { if ((p = lp.p) != NULL)
p->AddRef(); }
~CAutoPtr() { if (p) p->Release(); p= NULL;}

void Release() { if( NULL == p) return; p->Release();p = NULL;
}

_NoAddRefReleaseOnCAutoPtr<T>* operator->() const { return
(_NoAddRefReleaseOnCAutoPtr<T>*)p;}
operator T*() const { return p; }
T& operator*() const { assert( NULL != p ); return *p;}
T** operator&() { assert (NULL == p); return &p;}
T* operator=(T* lp) { if( p == lp) return p; if( p)
p->Release(); p=lp; if(p) p->AddRef(); return p;}
const CAutoPtr<T>& operator=(const CAutoPtr<T>& rhs) { if( p ==
rhs.p) return *this; if( p) p->Release(); p= rhs.p; if( p) p->AddRef();
return *this;}
bool operator==(T* pT) const { return p == pT;}

void Attach(T* p2) { if (p) p->Release(); p = p2; }
T* Detach() { T* pt = p; p = NULL;return pt;}
T* p;
};

class CHelpMe : public CRefCnt {};

typedef CAutoPtr<CHelpMe> CHelpMePtr;
typedef std::vector<CHelpMePtr> CHelpMePtrVector;

int main()
{
CHelpMePtrVector v( 10 );
return 0;
}


And here's the compiler output:

/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:
In function 'void std::_Destroy(_ForwardIterator, _ForwardIterator,
_Allocator) [with _ForwardIterator = CHelpMePtr*, _Allocator =
std::allocator<CHelpMePtr>]':
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_vector.h:273:
instantiated from 'std::vector<_Tp, _Alloc>::~vector() [with _Tp =
CHelpMePtr, _Alloc = std::allocator<CHelpMePtr>]'
/Users/reb/test1/main.cpp:71: instantiated from here
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h:174:
error: no matching function for call to
'std::allocator<CHelpMePtr>::destroy(CHelpMe**)'
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h:107:
note: candidates are: void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*)
[with _Tp = CHelpMePtr]

In playing with the code some more, if I comment the CAutoPtr
operator&, I still get a compiler error, but it's quite different:

/usr/bin/ld:
/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/libgcc_eh.a(unwind-dw2.o)
has external relocation entries in non-writable section (__TEXT,__text)
for symbols:
restFP
saveFP
collect2: ld returned 1 exit status

Any idea what might be ticking off the 4.0 compiler? If not, any
suggestions for where I might find an answer? Thanks again. -R

Hmm, since this seems to be GNU-specific, I'd suggest you post on the
gnu.g++.* newsgroups. They should have more expertise in this area.
Alternately, you could try a different STL implementation such as
STLport (http://www.stlport.com/).

In any case, it does seem that the operator& overload is likely the
culprit of your first set of problems. I'm not sure about the second
set, but it looks related to exception handling.

Cheers! --M
 

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

Forum statistics

Threads
474,262
Messages
2,571,049
Members
48,769
Latest member
Clifft

Latest Threads

Top