[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: help with STL
From: |
llewelly |
Subject: |
Re: help with STL |
Date: |
Thu, 06 May 2004 10:41:07 -0600 |
User-agent: |
Gnus/5.1002 (Gnus v5.10.2) Emacs/21.3.50 (berkeley-unix) |
"Martin" <imxng@bootweb.nl> writes:
> Hi,
>
> I am trying to use the STL-'set' container, but have a few problems with it.
>
> I have defined a certain class 'someclass' which is abstract. In that class
> I have defined the <, > and == operators for it. Whenever 2 classes derived
> from 'someclass' have the same key, I want them to be considered equal.
> 'class101' and 'class545' are derived from 'someclass'.
> In main() I want pointers to objects of type 'someclass' to be stored in a
> 'set', which means that no 2 elements of the set can be equal (in my case:
> no two objects that pointers point to, can have the same key).
The set you declare below is sorted according to pointer vaules,
*not* according to someclass::key .
set<my_type> defines a set sorted according to 'my_type' . Therefor,
set<someclass*> defines a set sorted according to 'someclass*' ,
*not* 'someclass'. The < operator for pointers is a builtin
operator which has unspecified behavior if the two pointers
compared point to objects which are not members of the same
object or elements of the same array. This is quite different
from comparing someclass::key .
> However, when
> I try inserting 2 objects of type class545, the set successfully
> does so,
The two objects you create have different addresses. In C++, all
objects of a given type have unique addresses. So it is only
natural that the operation succeeds.
> when in fact it should NOT because only one class with key '545' is allowed.
> Also, looking for an object of class101 (obj4 in my example) fails, which
> shouldn't, because obj2 of class101 actually is in the set.
> Finally, 'manually' comparing obj1 to obj3 works out just fine, which leaves
> me wondering why the set-insert/find functions don't use the operators I
> defined in someclass. Am I missing something here?
Yes. You can define a set with a comparison function tuned to your
needs, rather than relying on the default use of operator< . Like
this:
struct compare_someclass
{
bool operator()(someclass const* lhs, someclass const* rhs)
{
return *lhs < *rhs;
}
};
set<someclass*,compare_someclass> list;
>
> Thanks alot for any help!
>
> Martin
>
> #include<string>
> #include<iostream>
> #include<set>
>
> using namespace std;
>
> class someclass
> {
> public:
> string key;
> string data;
>
> virtual void dosomething() = 0;
> virtual ~someclass() = 0;
>
> bool operator<(someclass &rhs)
> {
> return key < rhs.key;
> }
>
> bool operator==(someclass &rhs)
> {
> return key == rhs.key;
> }
>
> bool operator>(someclass &rhs)
> {
> return key > rhs.key;
> }
> };
Not related to your problem, but these defintions of comparison
operators have several problems:
(0) The arguments are passed by reference to non-const. This
means the right hand operand can't be a const object:
int main()
{
class101 const foo;
class101 const bar;
foo < bar; //Error; reference to non-const cannot be bound
// to a const object.
}
(1) The fact that they are member operators causes them to treat
their left hand and right hand arguments in fundamentally
different ways:
int main()
{
class101 foo;
class101 const bar;
foo < bar ; //Error.
bar < foo ; // Ok!
}
(2) Only operator< needs access to key - the others can all be
defined interms of <.
The solution is to define < as a friend operator and the rest as
non-member operators, and all thier parameters as reference to
const:
//inside class definition:
friend bool operator<(someclass const& lhs,someclass const& rhs)
{
return lhs.key < rhs.key;
}
//outside class definition:
bool operator>(someclass const& lhs, someclass const& rhs)
{
return rhs < lhs;
}
bool operator==(someclass const& lhs, someclass const& rhs)
{
return not (lhs < rhs) and not (rhs < lhs);
}
>
> someclass::~someclass()
> {
> }
>
> class class101 : public someclass
> {
> public:
> class101( string d)
> {
> key = "101";
> data = d;
> }
>
> void dosomething()
> {
> cout << key << " : " << data << endl;
> }
> };
>
> class class545 : public someclass
> {
> public:
> class545( string d)
> {
> key = "545";
> data = d;
> }
>
> void dosomething()
> {
> cout << key << " => " << data << endl;
> }
> };
>
> int main()
> {
> set<someclass*> list;
This defines a set which is sorted according to the addresses of the
objects pointed to by the pointers. It will compare the pointers
to sort pointers which are inserted into it. It will *not* use
the operator< you defined for someclass above. Is this what you
want?
> set<someclass*>::iterator it;
>
> someclass *obj1 = new class545("dfdf");
> someclass *obj2 = new class101("fdgfdhgfhgf");
> someclass *obj3 = new class545("ds");
>
> someclass *obj4 = new class101("gdfgfd");
>
> list.insert(obj1);
> list.insert(obj2);
> list.insert(obj3);
>
> for(it = list.begin(); it != list.end(); it++)
> {
> (*it)->dosomething();
> }
>
> it = list.find(obj4);
The pointer obj4 has not been inserted into the list. It will not be found.
> if( it == list.end() )
> {
> cout << "NOT FOUND!" << endl;
> }else{
> cout << "FOUND!" << endl;
> }
>
>
> if( (*obj1) == (*obj3) )
> {
> cout << "obj1 and obj3 are equal" << endl;
> }
>
> return(0);
Since the OS will recycle the memory use by your program, I'll let
some other poster address the bad habit of allocating with new but
not using delete.
> }