help-gplusplus
[Top][All Lists]
Advanced

[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.

> }


reply via email to

[Prev in Thread] Current Thread [Next in Thread]