CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 23
  1. #1
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    85

    How to find & remove object from a std::list ?

    I'm trying to find an object in an std::list of objects, and remove it and I was going to look for the NAME of the object as a basis of comparison, something like this:
    PHP Code:

    class myObj
    {
    string name;
    int A;
    int B;
    //......
    int Z;

    }
    //then later in  the code....

        
    list<myObjmyList;
        list<
    myObj>::iterator itr;

        
    itr find(myList.begin(),myList.end(), /*look for myObj name */ ); 
        if (
    itr != myList.end())
        {
            
    itr myList.erase(itr);
        } 
    Question is, how do I lok for just the NAME using the find command?

    Thanks for the help!

  2. #2
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721
    1) I think you want to use find_if() instead of find() , since
    you are not checking the ENTIRE object for equality,
    just part of the object.

    2) the tricky part in creating the predicate, is you want
    to pass it the name that you are looking for. There
    is a "bnd2nd()" function that does this. I think sample
    code will make it clearer :

    Code:
    #include <list>
    #include <string>
    #include <functional>  // for binary_function and bnd2nd()
    #include <algorithm>   // for find_if
    
    using namespace std;
    
    class myObj
    {
    public:
    
        string name;
        int A;
        int B;
        int Z;
    
    };
    
    struct CompareName : public std::binary_function<myObj,std::string,bool >
    {
        bool operator () (const myObj& obj, const std::string& name) const
       {
           return obj.name == name;
       }
    };
    
    int main()
    {
        list<myObj> myList;
        list<myObj>::iterator itr;
    
        // add to list
    
        // remove FIRST occurence of object with name of "Jones"
        itr = find_if(myList.begin(),myList.end(),  bind2nd(CompareName(),"Jones")); 
        if (itr != myList.end())
        {
            itr = myList.erase(itr);
        }
    
        return 0;
    }

  3. #3
    Join Date
    Jul 2001
    Location
    Netherlands
    Posts
    751
    I wasn't done yet.

    Then again if your list gets very large you're better of using a map or set instead.
    the cool thing with sets is you can overload the comparison function with your own struct.

    struct MyCompare
    {
    bool operator()(YourObject *p1,YourObject * p2)const
    {
    //compare anyway your want and return true if bigger,or false if //smaller
    }
    };
    typedef std::set<YourObject*,MyCompare> MySet;
    Last edited by fransn; October 9th, 2003 at 02:03 PM.

  4. #4
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    85
    Thanks for the help guys!

  5. #5
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    For some reason, I've always had problems with bind2nd, so I usually rewrite my functor so that the item to be compared against is a member variable:
    Code:
    struct CompareName : public std::unary_function<myObj, bool >
    {
        CompareName(const std::string& n) : name(n) {}
        CompareName(const char* s) : name(s) {}
    
        bool operator () (const myObj& obj) const
        {
             return obj.name == name;
        }
    private:
         std::string name;
    };
    Then you call it like:
    Code:
    itr = find_if(myList.begin(),myList.end(),  CompareName("Jones"));
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  6. #6
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721
    Graham,

    that's a nice solution, and cerainly makes the calling
    sequence more understandable.

  7. #7
    Join Date
    Sep 2003
    Location
    Boston, Ma
    Posts
    52
    Sorry for bumping the thread but I didn't want to create a new one as I found this one.
    I kinda need to do the same thing but the problem with me is that my object name is a private member of myObj class.
    I have a get accessor though something like:
    Code:
    string getObjectName(){return name};
    but when I implement it in the code above the following way:
    Code:
    return obj.getObjectName()== name;
    I get the following error:
    Code:
    passing `
       const myObj' as `this' argument of `std::string myObj::getObjectName()' 
       discards qualifiers
    I tried to change around some data types but I still get the same error.
    Any help would be appreciated.
    Thanks.
    Sofia.

    Edit:Sorry I forgot to mention that if I use obj.name after taking of name from the private area and to the public my code compiles fine without any errors but I know that it's not the way to do it .
    Last edited by megabyte; October 14th, 2003 at 04:56 AM.

  8. #8
    Join Date
    Nov 1999
    Location
    Copenhagen, Denmark
    Posts
    265
    Your problem is that CompareName :: operator() takes as it's argument a const reference to a myObj and your myObj::getObjectName() method is not declared as const. Try changing it's signature to:

    Code:
    string getObjectName() const {return name};
    Best regards,
    S. Bro

    "I would be happy to deal with my problems one at the time if they would only line up!"
    -Paul Cilwa, "Borland C++ Insider".

    Other useful fora some of which I ruthlessly clipboarded from other peoples footers.

    MSDN: http://search.microsoft.com/us/dev/default.asp
    WIN 32 Assembler: http://board.win32asmcommunity.net/
    RDBMS: http://www.dbforums.com
    Robert's Perl Tutorial: http://www.sthomas.net/roberts-perl-tutorial.htm
    Merriam-Webster Online: http://www.m-w.com/home.htm
    Writing Unmaintainable Code: http://mindprod.com/unmain.html

  9. #9
    Join Date
    Sep 2003
    Location
    Boston, Ma
    Posts
    52
    Thank you ver much

  10. #10
    Join Date
    Sep 2003
    Location
    Boston, Ma
    Posts
    52
    Sorry to bother you guys again, but I'm encountring a small problem that I think is due to my lack of knowledge as the whole std::list world is very new to me(I spent so much time learning vectors that I can't grasp well all what's going on with lists).
    'nough said, what I'm trying to do is instead of using the following in main()
    Code:
    itr = find_if(myList.begin(),myList.end(),  CompareName("Jones"));
    I want to use it in a let's say a member function of myObj.
    I do so but I don't know how to keep the changes.Meaning that when I erase a member of the list and try to ouput the list I see that the removal was successful but what I need to do is append the changes to the list I'm working on in my main().
    Code:
    Myobj.EraseMember(Myobj,"Jones ");
    When I define EraseMember(list,key) I make sure to make it's return type as list and then return the list at the end but still the list in the main scope stays unchanged while the one inside the function defenition scope changes.
    I'm sure that I'm looking at it the wrong way so please advise.
    Thanks in advance.
    Sofia.

  11. #11
    Join Date
    Nov 1999
    Location
    Copenhagen, Denmark
    Posts
    265
    It seems to me you're moving into muddy waters here. You store myObjs in a list and then make the individual objects responsible for deleting themselves and eachother from that list. I think there's something wrong with this approach.

    Also, your method:

    Code:
    Myobj.EraseMember(Myobj,"Jones ");

    takes as it's first argument a pointer to a myObj even though EraseMember() is a member function and, as such, has access to the this pointer.

    What are you trying to do? Erase a myObj from the list through another myObj contained in the same list? I suspect you're complicating matters unnecessarily...
    Best regards,
    S. Bro

    "I would be happy to deal with my problems one at the time if they would only line up!"
    -Paul Cilwa, "Borland C++ Insider".

    Other useful fora some of which I ruthlessly clipboarded from other peoples footers.

    MSDN: http://search.microsoft.com/us/dev/default.asp
    WIN 32 Assembler: http://board.win32asmcommunity.net/
    RDBMS: http://www.dbforums.com
    Robert's Perl Tutorial: http://www.sthomas.net/roberts-perl-tutorial.htm
    Merriam-Webster Online: http://www.m-w.com/home.htm
    Writing Unmaintainable Code: http://mindprod.com/unmain.html

  12. #12
    Join Date
    Sep 2003
    Location
    Boston, Ma
    Posts
    52
    Sorry if I didn't make myself clear enough but I'll try to catch up.
    What I am trying to do is write a member function like let's say pop_front() or pop_back but which would erase an element of the list that is not in the front or the back but somewhere in the middle. the element would be chosen regarding it's name.
    so let say I have a list of obj which have a name and an age.
    so instead of saying something like
    MyList.pop_front(); I would like to be able to pop an element with a name let's say "James". something like MyList.EraseMember("James");
    Any help would be really appreciated.
    Sofia.

  13. #13
    Join Date
    Nov 1999
    Location
    Copenhagen, Denmark
    Posts
    265
    You're not deriving from std::list are you? If you are see this thread:

    STL and derivation

    Anyway, you could use containment:

    Code:
    class MyList 
    {
    public:
    	typedef list<myObj> OBJLIST, *POBJLIST;
    
    private:
    	MYOBJLIST	m_list;
    
    
    	struct CompareName : public std::unary_function<myObj, bool >
    	{
    	    CompareName(const std::string& n) : name(n) {}
    	    CompareName(const char* s) : name(s) {}
    	
    	    bool operator () (const myObj& obj) const
    	    {
    			return obj.getName() == name;
    		}
    	private:
    		std::string name;
    	};
    
    public:
    	MyList() {}
    	virtual ~MyList() {}
    	
    	myObj pop_first(const string &name)
    	{
    		// find_if/erase code here
    	}
    }
    Note that this is probably not the only approach, nor is it nessecarily the best. It's just a suggestion.
    Best regards,
    S. Bro

    "I would be happy to deal with my problems one at the time if they would only line up!"
    -Paul Cilwa, "Borland C++ Insider".

    Other useful fora some of which I ruthlessly clipboarded from other peoples footers.

    MSDN: http://search.microsoft.com/us/dev/default.asp
    WIN 32 Assembler: http://board.win32asmcommunity.net/
    RDBMS: http://www.dbforums.com
    Robert's Perl Tutorial: http://www.sthomas.net/roberts-perl-tutorial.htm
    Merriam-Webster Online: http://www.m-w.com/home.htm
    Writing Unmaintainable Code: http://mindprod.com/unmain.html

  14. #14
    Join Date
    Sep 2003
    Location
    Boston, Ma
    Posts
    52

    Unhappy

    Morning everyone,
    Thank you for the reply sbrothy.I'm actually deriving from the STL list and eventhough I got to understand why I shouldn't be doing that I just have to do it as I have no choice
    I didn't really grasp the idea of containment!! I would really appreciate it if you were to give me an idea on what it means.
    Does it have to do with this line??
    Code:
    typedef list<myObj> OBJLIST, *POBJLIST;
    I actually worked up my code a bit and now it compiles but the application crashes
    this is the code I have:
    Code:
    template<class T>
    class OrderedList: public list<T> {
      public:
        OrderedList();
       ~OrderedList();
        void EraseMember(OrderedList<T>& MyList,string myKey);
      
      
    };
    and then in my main I call it this way:

    Code:
     OrderedList<Myobj> workers;
      ifstream inputFile("c:\\NewYork.txt");
      ofstream outputFile("C:\\output.txt",ios:: out|ios::trunc);
      Myobj anobj;
      while(inputFile>>anobj)
      Workers.push_back(anobj);
     
      Workers.EraseMember(Workers,"James");


    Code:
    template<class T> 
    void OrderedList<T>::EraseMember(OrderedList<T>& MyList,string myKey)
    { 
      typename OrderedList<T>::iterator itr;
      itr = find_if(MyList.begin(),MyList.end(),  CompareName(myKey));
      itr = MyList.erase(itr);
        
    }
    once again I know that I am not supposed to inherit from the an stl container(as it's not a base class and hence has no virtual destructors...) .
    Thanks for any help.
    Sofia.

  15. #15
    Join Date
    Nov 1999
    Location
    Copenhagen, Denmark
    Posts
    265
    The concept of containment is simply that you include the class you would normally derive from as a member of the new class.
    Hence:

    The class A:

    Code:
    class A {
    public:
    	int foo() const { return 5; }
    }

    Derivation from class A:

    Code:
    class B : public class A {
    	// foo() is inherited.
    }

    Containment of class A:

    Code:
    class B {
    private:
    	A m_a;
    public:
    	int foo() const { return m_a.foo(); } // foo is exposed through the contained class A.
    }
    Using the latter way is extra coding as you'd have to expose all the A member functions that you'd like to use
    from without the class:


    Code:
    #include <list>
    #include <string>
    #include <functional>  // for binary_function and bnd2nd()
    #include <algorithm>   // for find_if
    #include <iostream>
    
    using namespace std;
    
    class myObj
    {
        string name;
    
    public:
        int A;
        int B;
        int Z;
    
    	void setName(const string &name) { this->name = name; }
    	string getName() const { return name; }
    };
    
    
    class MyList 
    {
    private:
    	list<myObj>	m_list;
    
    
    	struct CompareName : public std::unary_function<myObj, bool >
    	{
    	    CompareName(const std::string& n) : name(n) {}
    	    CompareName(const char* s) : name(s) {}
    	
    	    bool operator () (const myObj& obj) const
    	    {
    			return obj.getName() == name;
    		}
    	private:
    		std::string name;
    	};
    
    public:
    	MyList() {}
    	virtual ~MyList() {}
    
    	list<myObj>::size_type size() const
    	{
    		return m_list.size();
    	}
    
    	void push_back(const myObj &obj)
    	{
    		m_list.push_back(obj);
    	}
    
    	void pop_first(const string &name)
    	{
    		// remove FIRST occurence of object with name of 'name' and return the removed element
    		list<myObj>::iterator itr = find_if(m_list.begin(), m_list.end(), CompareName(name));
    	    if (itr != m_list.end())
    		    m_list.erase(itr);
    	}
    };
    
    int main()
    {
    	MyList li;
    	
    	myObj o;
    
    	o.setName("A");
    	li.push_back(o);
    
    	o.setName("B");
    	li.push_back(o);
    
    	o.setName("C");
    	li.push_back(o);
    
    	cout << li.size() << endl;
    
    	li.pop_first("B");
    
    	cout << li.size() << endl;
    
        return 0;
    }

    Ofcourse this would so much simpler if you were allowed to derive from std::list. :-)
    Best regards,
    S. Bro

    "I would be happy to deal with my problems one at the time if they would only line up!"
    -Paul Cilwa, "Borland C++ Insider".

    Other useful fora some of which I ruthlessly clipboarded from other peoples footers.

    MSDN: http://search.microsoft.com/us/dev/default.asp
    WIN 32 Assembler: http://board.win32asmcommunity.net/
    RDBMS: http://www.dbforums.com
    Robert's Perl Tutorial: http://www.sthomas.net/roberts-perl-tutorial.htm
    Merriam-Webster Online: http://www.m-w.com/home.htm
    Writing Unmaintainable Code: http://mindprod.com/unmain.html

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured