N
NKOBAYE027
my friends, the end()...
hehehe no...nothing so dire...
I'm at an impasse I think. I've created the MathematicalSet class as
follows - it has 4 lists. An ObjectPool of the actual objects, a static
Universe of countable pointers, a static Null set (unpopulated) and a Set of
countable pointers. Each time I add an object I check the pool to see if it
exists already, if not, I add it to the pool, then I push countable pointers
to the object in the pool onto the Universe and the Set. Now I want users to
be able to access and iterate over the Mathematical set as though it were a
regular STL container. This means that dereferencing a
MathematicalSet::iterator will return a reference to an object of whatever
type the set contains - those stored in the pool. This has all been done to
a point. The next issue comes with iterating over the Set.
MathematicalSet::const_iterator it = begin();
MathematicalSet::const_iterator ick = end();
while(it++ != ick);
Now since I want the iterators to behave as though they're actually pointing
to objects instead of countable pointers to unique objects I've had to
overload a couple of functions for the Set::iterator. Namely the *, ->, ==
and != - these operators return a refererence to a pooled object, a pointer
to a pooled object and booleans. The MathematicalSet::begin() and end()
functions simply return iterators initialised to Set::begin() and end(). So,
the problem comes in when I use != (or any other time, actually) and have to
dereference MathematicalSet::end(). The iterator def'ns are nested within
the MathematicalSet class and I can't access the Set member (compiler says
it must be static, enumeration or type name) for it's 'end' to write code
within the iterator def's so that I can avoid this problem (and, I'm not
sure I can avoid the problem that way even if I could access the Set
member). I'll post the complete code below, but it's fairly extensive. I
need some good suggestions or advice on how to get through this 'end()'
dereferencing issue with the embedded iterator def's. I can't seem to
determine how the compiler does it with it's own code, though I suspect it's
just a pointer comparison. My problem is I want to keep only one copy of
each object in the pool, so I have to do a member comparison using the
object's == rather than just compare addresses. Speak, oh ye gurus, sages,
pundits and code wizards...tell me it can be done using the regular STL
list, or am I going to have to write my list from scratch. I really want to
use STL for the memory management, I'm too much of a beginner to think of
writing a list that manages it's own resources....this is bugging the heck
out me, the wife, the cat (if I kick him once more I think she'll disown
me).... )
regards,
L.
PS: The code below compiles without error on my MSVC 6.0
// MathSetDriver.cpp
#include "MathematicalSet.hpp"
#include <iostream>
using namespace mathematical_set;
class bob
{
public:
int a;
char b;
bob():a(0),b(0){}
bob(const bob& d)
{
a = d.a;
b = d.b;
}
bob& operator=(const bob& d)
{
if(this != &d)
{
a = d.a;
b = d.b;
}
return *this;
}
bool operator==(const bob& d) const
{
return (a == d.a) ? ( b == d.b) : false;
}
bool operator!=(const bob& d)
{
return !(*this == d);
}
~bob(){}
};
int main()
{
bob b, b1, b2;
b1.a = 1;
b2.a = 2;
b1.b = 1;
b2.b = 2;
MathematicalSet<bob> aSet;
aSet.add(b);
aSet.add(b);
aSet.add(b2);
aSet.add(b1);
MathematicalSet< bob >::iterator ia = aSet.begin();
MathematicalSet< bob >::iterator ib = aSet.begin();
ib++;
ib->a=0;
ib->b=0;
if( ia == ib)
cout << "wheeee\n";
const MathematicalSet< bob > bSet = aSet;
MathematicalSet< bob >::const_iterator ita = aSet.begin();
MathematicalSet< bob >::const_iterator itb = bSet.begin();
bob a = *itb;
if(ita == itb)
cout << "wheeeeeeeeee\n";
// this code crashes...
// MathematicalSet< bob >::iterator i = begin();
// MathematicalSet< bob >::iterator e = end();
// while(i != e) i++;
return 0;
}
// Element.hpp
// File: Element.hpp
// Countable element template for use with the Mathematical set class and
counted pointers.
#pragma once // include this file once
#pragma warning( disable : 4786 ) // disable the "name too long" warning
// hide this creature in its own namespace
namespace mathematical_element
{
// reference counted wrapper for objects
template< typename object >
class Element
{
public:
// all the pointers (must be initialised to 0 in each ctor)
unsigned m_NumberOfPointers;
// the object
object m_TheObject;
// default ctor.
Element< object >():m_NumberOfPointers(0), m_TheObject()
{ /* nothing to do here */ }
// copy ctor
Element< object >(const Element< object >& s) : m_NumberOfPointers(0),
m_TheObject(s.m_TheObject)
{ /* nothing to do here */ }
// elemental ctor
Element< object >(const object& anObject) : m_NumberOfPointers(0),
m_TheObject(anObject)
{ /* nothing to do here */ }
// assignment operator
const Element< object >& operator=(const Element< object >& anElement)
const
{
// avoid self-assignment
if(this != &anElement)
{
// set member values
m_NumberOfPointers = anElement.m_NumberOfPointers;
m_TheObject = anElement.m_TheObject;
}
return *this;
}
// comparison operator
const bool operator==(const Element< object >& anElement) const
{
return m_TheObject == anElement.m_TheObject;
}
// dtor
~Element(){ /* nothing to do here */ }
};
};
// CountedPointer.hpp
// File: CountedPointer.hpp
// A counted pointer template to be used with the countable element
// described in element.hpp.
#pragma once // include this file once
#pragma warning( disable : 4786 ) // disable the "name too long" warning
// hide this creature in its own namespace
namespace counted_pointer
{
template< typename element >
class CountedPointer
{
public:
// private constructor to limit user access
CountedPointer< element >(){}
// can make the pointer public since author is only one using it
element* m_ThePointer;
// overload operator ->
element* operator->()
{
return m_ThePointer;
}
// overload operator ->
const element* operator->() const
{
return m_ThePointer;
}
// operator *
element& operator*()
{ return *m_ThePointer; }
// operator *
const element& operator*() const
{ return *m_ThePointer; }
// explicit ctor
CountedPointer< element >(element* aPointer):m_ThePointer(aPointer)
{ ++m_ThePointer->m_NumberOfPointers; }
// explicit ctor
CountedPointer< element >(element& anElement):m_ThePointer(&anElement)
{ ++m_ThePointer->m_NumberOfPointers; }
// dtor
~CountedPointer< element >()
{ --m_ThePointer->m_NumberOfPointers; }
// copy ctor
CountedPointer< element >(const CountedPointer< element >&
aCountedPointer) : m_ThePointer(aCountedPointer.m_ThePointer)
{ ++m_ThePointer->m_NumberOfPointers; }
// assignment operator
CountedPointer< element >& operator=(const CountedPointer< element >&
aCountedPointer)
{
++aCountedPointer.m_ThePointer->m_NumberOfPointers;
--m_ThePointer->m_NumberOfPointers;
m_ThePointer = aCountedPointer.m_ThePointer;
return *this;
}
// comparison operator
const bool operator==(const CountedPointer< element >& aCountedPointer)
{
if( aCountedPointer.m_ThePointer == m_ThePointer )return true;
return *m_ThePointer == *(aCountedPointer.m_ThePointer);
}
// contrapositive comparison
const bool operator!=(const CountedPointer< element >& aCountedPointer)
{
return !(*this == aCountedPointer);
}
};
};
// MathematicalSet.hpp
#pragma once
#pragma warning( disable : 4786 )
#include <list> // basic list structure
#include <algorithm> // for the find function template, et. al.
#include "Element.hpp" // a countable element wrapper for objects
#include "CountedPointer.hpp" // a counted pointer friend for element
// hide this creature in it's own namespace
namespace mathematical_set
{
// the namespaces the set needs
using namespace std;
using namespace mathematical_element;
using namespace counted_pointer;
// the parameterised def'n of the MathematicalSet
template< typename object >
class MathematicalSet
{
public:
// standard typedefs
typedef MathematicalSet< object > MathSet;
typedef Element< object > MathElement;
typedef CountedPointer< MathElement > ElementPointer;
typedef object value_type;
typedef object& reference;
typedef const object& const_reference;
typedef object* pointer;
typedef const object* const_pointer;
typedef list< MathElement > ObjectPool;
typedef list< ElementPointer > Set;
class iterator;
class const_iterator;
class const_iterator : public Set::const_iterator
{
public:
typedef Set::const_iterator base_iterator;
const_iterator(){}
const_iterator(base_iterator aSetIterator) :
base_iterator(aSetIterator){}
const_reference operator*() const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject;
}
const_pointer operator->() const
{
return &**this;
}
bool operator==(const const_iterator& aConstIterator) const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject ==
*aConstIterator;
}
bool operator!=(const const_iterator& aConstIterator) const
{
return !(*this == aConstIterator);
}
};
class iterator : public Set::iterator
{
public:
typedef Set::iterator base_iterator;
iterator(){}
iterator(base_iterator aSetIterator) : base_iterator(aSetIterator){}
reference operator*() const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject;
}
pointer operator->() const
{
return &**this;
}
bool operator==(const iterator& anIterator) const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject ==
*anIterator;
}
bool operator!=(const iterator& anIterator) const
{
return !(*this == anIterator);
}
};
iterator begin()
{
return iterator(m_TheSet.begin());
}
const_iterator begin() const
{
return const_iterator(m_TheSet.begin());
}
iterator end()
{
return iterator(m_TheSet.end());
}
const_iterator end() const
{
return const_iterator(m_TheSet.end());
}
private:
friend class iterator;
friend class const_iterator;
static ObjectPool m_ObjectPool;
static MathematicalSet m_TheUniverse;
static MathematicalSet m_TheNullSet;
// the user's set
Set m_TheSet;
protected:
/* no protected members or functions yet */
public:
MathSet() : m_TheSet( list< ElementPointer >() )
{ /* nothing to do here */ }
MathSet(const MathSet& aSet):m_TheSet( aSet.m_TheSet )
{ /* nothing to do here */ }
~MathematicalSet()
{ /* nothing to do here */ }
const MathSet& operator=(const MathSet& aSet)
{
if(*this != aSet)
{
m_TheSet = aSet.m_TheSet;
}
return *this;
}
const bool operator==(const MathSet& aSet)
{ return m_TheSet == aSet.m_TheSet; }
const bool operator<(const MathSet& aSet)
{ return m_TheSet < aSet.m_TheSet; }
void add(object& anObject);
void remove(object& anObject);
};
// externalise the typedefs
template< typename object >
typedef MathematicalSet< object >::MathSet MathSet;
template< typename object >
typedef MathematicalSet< object >::MathElement MathElement;
template< typename object >
typedef MathematicalSet< object >::ElementPointer ElementPointer;
template< typename object >
typedef MathematicalSet< object >::ObjectPool ObjectPool;
template< typename object >
typedef MathematicalSet< object >::Set Set;
// initialise the globals
template< typename object >
MathematicalSet< object > MathematicalSet< object >::m_TheNullSet;
template< typename object >
MathematicalSet< object > MathematicalSet< object >::m_TheUniverse;
template< typename object >
inline void MathematicalSet< object >::add(object& anObject)
{
// create an element and a reference pointing to it
MathElement& anElement = MathElement(anObject);
// find the object in the object pool
ObjectPool::iterator& foundObject = find(m_ObjectPool.begin(),
m_ObjectPool.end(), anObject);
// if the object doesn't already exist in the pool then create one
if( foundObject == m_ObjectPool.end())
{
// add it to the global pool
m_ObjectPool.push_back(anElement);
foundObject = --m_ObjectPool.end();
}
ElementPointer& anElementPointer = ElementPointer(*foundObject);
// update the universal set
m_TheUniverse.m_TheSet.push_back(anElementPointer);
// add the element pointer to the local set
m_TheSet.push_back(anElementPointer);
}
};
hehehe no...nothing so dire...
I'm at an impasse I think. I've created the MathematicalSet class as
follows - it has 4 lists. An ObjectPool of the actual objects, a static
Universe of countable pointers, a static Null set (unpopulated) and a Set of
countable pointers. Each time I add an object I check the pool to see if it
exists already, if not, I add it to the pool, then I push countable pointers
to the object in the pool onto the Universe and the Set. Now I want users to
be able to access and iterate over the Mathematical set as though it were a
regular STL container. This means that dereferencing a
MathematicalSet::iterator will return a reference to an object of whatever
type the set contains - those stored in the pool. This has all been done to
a point. The next issue comes with iterating over the Set.
MathematicalSet::const_iterator it = begin();
MathematicalSet::const_iterator ick = end();
while(it++ != ick);
Now since I want the iterators to behave as though they're actually pointing
to objects instead of countable pointers to unique objects I've had to
overload a couple of functions for the Set::iterator. Namely the *, ->, ==
and != - these operators return a refererence to a pooled object, a pointer
to a pooled object and booleans. The MathematicalSet::begin() and end()
functions simply return iterators initialised to Set::begin() and end(). So,
the problem comes in when I use != (or any other time, actually) and have to
dereference MathematicalSet::end(). The iterator def'ns are nested within
the MathematicalSet class and I can't access the Set member (compiler says
it must be static, enumeration or type name) for it's 'end' to write code
within the iterator def's so that I can avoid this problem (and, I'm not
sure I can avoid the problem that way even if I could access the Set
member). I'll post the complete code below, but it's fairly extensive. I
need some good suggestions or advice on how to get through this 'end()'
dereferencing issue with the embedded iterator def's. I can't seem to
determine how the compiler does it with it's own code, though I suspect it's
just a pointer comparison. My problem is I want to keep only one copy of
each object in the pool, so I have to do a member comparison using the
object's == rather than just compare addresses. Speak, oh ye gurus, sages,
pundits and code wizards...tell me it can be done using the regular STL
list, or am I going to have to write my list from scratch. I really want to
use STL for the memory management, I'm too much of a beginner to think of
writing a list that manages it's own resources....this is bugging the heck
out me, the wife, the cat (if I kick him once more I think she'll disown
me).... )
regards,
L.
PS: The code below compiles without error on my MSVC 6.0
// MathSetDriver.cpp
#include "MathematicalSet.hpp"
#include <iostream>
using namespace mathematical_set;
class bob
{
public:
int a;
char b;
bob():a(0),b(0){}
bob(const bob& d)
{
a = d.a;
b = d.b;
}
bob& operator=(const bob& d)
{
if(this != &d)
{
a = d.a;
b = d.b;
}
return *this;
}
bool operator==(const bob& d) const
{
return (a == d.a) ? ( b == d.b) : false;
}
bool operator!=(const bob& d)
{
return !(*this == d);
}
~bob(){}
};
int main()
{
bob b, b1, b2;
b1.a = 1;
b2.a = 2;
b1.b = 1;
b2.b = 2;
MathematicalSet<bob> aSet;
aSet.add(b);
aSet.add(b);
aSet.add(b2);
aSet.add(b1);
MathematicalSet< bob >::iterator ia = aSet.begin();
MathematicalSet< bob >::iterator ib = aSet.begin();
ib++;
ib->a=0;
ib->b=0;
if( ia == ib)
cout << "wheeee\n";
const MathematicalSet< bob > bSet = aSet;
MathematicalSet< bob >::const_iterator ita = aSet.begin();
MathematicalSet< bob >::const_iterator itb = bSet.begin();
bob a = *itb;
if(ita == itb)
cout << "wheeeeeeeeee\n";
// this code crashes...
// MathematicalSet< bob >::iterator i = begin();
// MathematicalSet< bob >::iterator e = end();
// while(i != e) i++;
return 0;
}
// Element.hpp
// File: Element.hpp
// Countable element template for use with the Mathematical set class and
counted pointers.
#pragma once // include this file once
#pragma warning( disable : 4786 ) // disable the "name too long" warning
// hide this creature in its own namespace
namespace mathematical_element
{
// reference counted wrapper for objects
template< typename object >
class Element
{
public:
// all the pointers (must be initialised to 0 in each ctor)
unsigned m_NumberOfPointers;
// the object
object m_TheObject;
// default ctor.
Element< object >():m_NumberOfPointers(0), m_TheObject()
{ /* nothing to do here */ }
// copy ctor
Element< object >(const Element< object >& s) : m_NumberOfPointers(0),
m_TheObject(s.m_TheObject)
{ /* nothing to do here */ }
// elemental ctor
Element< object >(const object& anObject) : m_NumberOfPointers(0),
m_TheObject(anObject)
{ /* nothing to do here */ }
// assignment operator
const Element< object >& operator=(const Element< object >& anElement)
const
{
// avoid self-assignment
if(this != &anElement)
{
// set member values
m_NumberOfPointers = anElement.m_NumberOfPointers;
m_TheObject = anElement.m_TheObject;
}
return *this;
}
// comparison operator
const bool operator==(const Element< object >& anElement) const
{
return m_TheObject == anElement.m_TheObject;
}
// dtor
~Element(){ /* nothing to do here */ }
};
};
// CountedPointer.hpp
// File: CountedPointer.hpp
// A counted pointer template to be used with the countable element
// described in element.hpp.
#pragma once // include this file once
#pragma warning( disable : 4786 ) // disable the "name too long" warning
// hide this creature in its own namespace
namespace counted_pointer
{
template< typename element >
class CountedPointer
{
public:
// private constructor to limit user access
CountedPointer< element >(){}
// can make the pointer public since author is only one using it
element* m_ThePointer;
// overload operator ->
element* operator->()
{
return m_ThePointer;
}
// overload operator ->
const element* operator->() const
{
return m_ThePointer;
}
// operator *
element& operator*()
{ return *m_ThePointer; }
// operator *
const element& operator*() const
{ return *m_ThePointer; }
// explicit ctor
CountedPointer< element >(element* aPointer):m_ThePointer(aPointer)
{ ++m_ThePointer->m_NumberOfPointers; }
// explicit ctor
CountedPointer< element >(element& anElement):m_ThePointer(&anElement)
{ ++m_ThePointer->m_NumberOfPointers; }
// dtor
~CountedPointer< element >()
{ --m_ThePointer->m_NumberOfPointers; }
// copy ctor
CountedPointer< element >(const CountedPointer< element >&
aCountedPointer) : m_ThePointer(aCountedPointer.m_ThePointer)
{ ++m_ThePointer->m_NumberOfPointers; }
// assignment operator
CountedPointer< element >& operator=(const CountedPointer< element >&
aCountedPointer)
{
++aCountedPointer.m_ThePointer->m_NumberOfPointers;
--m_ThePointer->m_NumberOfPointers;
m_ThePointer = aCountedPointer.m_ThePointer;
return *this;
}
// comparison operator
const bool operator==(const CountedPointer< element >& aCountedPointer)
{
if( aCountedPointer.m_ThePointer == m_ThePointer )return true;
return *m_ThePointer == *(aCountedPointer.m_ThePointer);
}
// contrapositive comparison
const bool operator!=(const CountedPointer< element >& aCountedPointer)
{
return !(*this == aCountedPointer);
}
};
};
// MathematicalSet.hpp
#pragma once
#pragma warning( disable : 4786 )
#include <list> // basic list structure
#include <algorithm> // for the find function template, et. al.
#include "Element.hpp" // a countable element wrapper for objects
#include "CountedPointer.hpp" // a counted pointer friend for element
// hide this creature in it's own namespace
namespace mathematical_set
{
// the namespaces the set needs
using namespace std;
using namespace mathematical_element;
using namespace counted_pointer;
// the parameterised def'n of the MathematicalSet
template< typename object >
class MathematicalSet
{
public:
// standard typedefs
typedef MathematicalSet< object > MathSet;
typedef Element< object > MathElement;
typedef CountedPointer< MathElement > ElementPointer;
typedef object value_type;
typedef object& reference;
typedef const object& const_reference;
typedef object* pointer;
typedef const object* const_pointer;
typedef list< MathElement > ObjectPool;
typedef list< ElementPointer > Set;
class iterator;
class const_iterator;
class const_iterator : public Set::const_iterator
{
public:
typedef Set::const_iterator base_iterator;
const_iterator(){}
const_iterator(base_iterator aSetIterator) :
base_iterator(aSetIterator){}
const_reference operator*() const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject;
}
const_pointer operator->() const
{
return &**this;
}
bool operator==(const const_iterator& aConstIterator) const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject ==
*aConstIterator;
}
bool operator!=(const const_iterator& aConstIterator) const
{
return !(*this == aConstIterator);
}
};
class iterator : public Set::iterator
{
public:
typedef Set::iterator base_iterator;
iterator(){}
iterator(base_iterator aSetIterator) : base_iterator(aSetIterator){}
reference operator*() const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject;
}
pointer operator->() const
{
return &**this;
}
bool operator==(const iterator& anIterator) const
{
return (*(static_cast<base_iterator>(*this)))->m_TheObject ==
*anIterator;
}
bool operator!=(const iterator& anIterator) const
{
return !(*this == anIterator);
}
};
iterator begin()
{
return iterator(m_TheSet.begin());
}
const_iterator begin() const
{
return const_iterator(m_TheSet.begin());
}
iterator end()
{
return iterator(m_TheSet.end());
}
const_iterator end() const
{
return const_iterator(m_TheSet.end());
}
private:
friend class iterator;
friend class const_iterator;
static ObjectPool m_ObjectPool;
static MathematicalSet m_TheUniverse;
static MathematicalSet m_TheNullSet;
// the user's set
Set m_TheSet;
protected:
/* no protected members or functions yet */
public:
MathSet() : m_TheSet( list< ElementPointer >() )
{ /* nothing to do here */ }
MathSet(const MathSet& aSet):m_TheSet( aSet.m_TheSet )
{ /* nothing to do here */ }
~MathematicalSet()
{ /* nothing to do here */ }
const MathSet& operator=(const MathSet& aSet)
{
if(*this != aSet)
{
m_TheSet = aSet.m_TheSet;
}
return *this;
}
const bool operator==(const MathSet& aSet)
{ return m_TheSet == aSet.m_TheSet; }
const bool operator<(const MathSet& aSet)
{ return m_TheSet < aSet.m_TheSet; }
void add(object& anObject);
void remove(object& anObject);
};
// externalise the typedefs
template< typename object >
typedef MathematicalSet< object >::MathSet MathSet;
template< typename object >
typedef MathematicalSet< object >::MathElement MathElement;
template< typename object >
typedef MathematicalSet< object >::ElementPointer ElementPointer;
template< typename object >
typedef MathematicalSet< object >::ObjectPool ObjectPool;
template< typename object >
typedef MathematicalSet< object >::Set Set;
// initialise the globals
template< typename object >
MathematicalSet< object > MathematicalSet< object >::m_TheNullSet;
template< typename object >
MathematicalSet< object > MathematicalSet< object >::m_TheUniverse;
template said:::m_ObjectPool;
template< typename object >
inline void MathematicalSet< object >::add(object& anObject)
{
// create an element and a reference pointing to it
MathElement& anElement = MathElement(anObject);
// find the object in the object pool
ObjectPool::iterator& foundObject = find(m_ObjectPool.begin(),
m_ObjectPool.end(), anObject);
// if the object doesn't already exist in the pool then create one
if( foundObject == m_ObjectPool.end())
{
// add it to the global pool
m_ObjectPool.push_back(anElement);
foundObject = --m_ObjectPool.end();
}
ElementPointer& anElementPointer = ElementPointer(*foundObject);
// update the universal set
m_TheUniverse.m_TheSet.push_back(anElementPointer);
// add the element pointer to the local set
m_TheSet.push_back(anElementPointer);
}
};