Thread: vector<object>::iterator Help

  1. #1
    VA National Guard The Brain's Avatar
    Join Date
    May 2004
    Location
    Manassas, VA USA
    Posts
    903

    Question vector<object>::iterator Help

    Trying to erase an element from a vector. I know this is an expensive operation, but I am not worried about performance.

    My function is based on this msdn excerpt which provides an example of how to create, initilize and use a vector class iterator object which I plan to pass into erase(), which accepts iterator agrument(s).

    As per the example, I have created an initialized an iterator; however, dev-cpp is giving me the following errors:

    327 F:\Dev-Cpp\database2.cpp `Manager::vStaff' cannot appear in a constant-expression
    327 F:\Dev-Cpp\database2.cpp template argument 1 is invalid
    327 F:\Dev-Cpp\database2.cpp template argument 2 is invalid
    327 F:\Dev-Cpp\database2.cpp `iterator' does not name a type
    328 F:\Dev-Cpp\database2.cpp `Iter' undeclared (first use this function)



    Here is the code, line #327 highlighted.
    Using namespace std:
    Code:
    void Manager::delete_staff()
    {
         vector<vStaff>::iterator Iter = vStaff.begin();     
         bool found = false;
         string name;
         int i = 0;     
         
         cout << "\n\n\tEnter name o' staff to delete: ";
         cin >> name;
         
         while(!found && i < vStaff.size())
         {
            if(vStaff[i] == name)
            
                 found = true;
                 
            i++;
         }
         
         if(!found)
         
            cout << "\n\n\t\.......... Name Not Found! **";
            
         else
         {
           vStaff.erase(Iter + i); 
           cout << "\n\n\tStaff Removed.";
           Sleep(1500);
         }
    }
    What am I missing/doing wrong?
    Last edited by The Brain; 03-26-2006 at 07:57 PM.
    • "Problem Solving C++, The Object of Programming" -Walter Savitch
    • "Data Structures and Other Objects using C++" -Walter Savitch
    • "Assembly Language for Intel-Based Computers" -Kip Irvine
    • "Programming Windows, 5th edition" -Charles Petzold
    • "Visual C++ MFC Programming by Example" -John E. Swanke
    • "Network Programming Windows" -Jones/Ohlund
    • "Sams Teach Yourself Game Programming in 24 Hours" -Michael Morrison
    • "Mathmatics for 3D Game Programming & Computer Graphics" -Eric Lengyel

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> vector<vStaff>::iterator Iter = vStaff.begin();

    vStaff is the name of your vector. Whatever type the vector holds is what should go inside the angle brackets (just like when you declare vStaff).
    Last edited by Daved; 03-26-2006 at 11:48 AM.

  3. #3
    VA National Guard The Brain's Avatar
    Join Date
    May 2004
    Location
    Manassas, VA USA
    Posts
    903
    ahh.. thank you very much !
    • "Problem Solving C++, The Object of Programming" -Walter Savitch
    • "Data Structures and Other Objects using C++" -Walter Savitch
    • "Assembly Language for Intel-Based Computers" -Kip Irvine
    • "Programming Windows, 5th edition" -Charles Petzold
    • "Visual C++ MFC Programming by Example" -John E. Swanke
    • "Network Programming Windows" -Jones/Ohlund
    • "Sams Teach Yourself Game Programming in 24 Hours" -Michael Morrison
    • "Mathmatics for 3D Game Programming & Computer Graphics" -Eric Lengyel

  4. #4
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    vector<vStaff>::iterator Iter = vStaff.begin();
    vStaff appears as both the type and the container. The vector template argument should be its type, not the container itself.

    Also, you can shorten your code a bit:
    Code:
    std::vector<std::string>::iterator i = vStaff.begin();
    while(i != vStaff.end())
    {
      if((*i) == name)
      {
        vStaff.erase(i);
        break;
      }
    
      i++;
    }
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    BTW, your algorithm is not quite right. There are also other options that can let you remove the proper item in one line of code.

  6. #6
    VA National Guard The Brain's Avatar
    Join Date
    May 2004
    Location
    Manassas, VA USA
    Posts
    903

    Question

    I am looking through the vector class members to find better options.. pop_back( ) appears to be the most efficient.. but I would like to remove elements from the vector from random locations..

    what would be a better option for removing / erasing elements from a vector?


    current code:
    Code:
    void Manager::delete_staff()
    {
         vector<string>::iterator Iter = vStaff.begin();     
         bool found = false;
         string name;
         int i = 0;     
         
         cout << "\n\n\tEnter name o' staff to delete: ";
         cin >> name;
         
         while(!found && i < vStaff.size())
         {
            if(vStaff[i] == name)
            
                 found = true;
                 
            i++;
         }
         
         if(!found)
         {     
            cout << "\n\n\t\.......... Name Not Found! **";
            Sleep(1500);
            return;
         }
            
         else
         {
           vStaff.erase(Iter + i); 
           cout << "\n\n\tStaff Removed.";
           Sleep(1500);
         }
    }

    **OK i see Magos's suggestion**
    very cool stuff.
    Last edited by The Brain; 03-26-2006 at 12:05 PM.
    • "Problem Solving C++, The Object of Programming" -Walter Savitch
    • "Data Structures and Other Objects using C++" -Walter Savitch
    • "Assembly Language for Intel-Based Computers" -Kip Irvine
    • "Programming Windows, 5th edition" -Charles Petzold
    • "Visual C++ MFC Programming by Example" -John E. Swanke
    • "Network Programming Windows" -Jones/Ohlund
    • "Sams Teach Yourself Game Programming in 24 Hours" -Michael Morrison
    • "Mathmatics for 3D Game Programming & Computer Graphics" -Eric Lengyel

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Code:
    vStaff.erase(std::remove(vStaff.begin(), vStaff.end(), name), vStaff.end());
    remove() is in <algorithm>. It shuffles the container so that all values that match name are put at the end, and then it returns the new logical end of the vector. That is used in the call to erase to actually erase the moved item(s).

    That code obviously doesn't tell you if anything was found or not, although you could just check the size of the vector before and after.

    If you don't want to use remove(), then Magos' version is a good choice.

  8. #8
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    I was just reading some docs on how to use std::remove (never really used it before). Any particular reason why it doesn't actually remove the elements?
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  9. #9
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    According to Josuttis, it's to maintain the flexibility of the STL:
    Quote Originally Posted by The C++ Standard Library, p. 114
    The STL separates data structures and algorithms by using iterators as the interface. However, iterators are an abstraction to represent a position in a container. In general, iterators do not know their containers. Thus, the algorithms, which use the iterators to access the elements of the container, can't call any member function for it.

    This design has important consequences because it allows algorithms to operate on ranges that are different from "all elements of a container." For example, the range might be a subset of all elements of a collection. And, it might even be a container that provides no erase() member function (ordinary arrays are an example of such a container). So, to make algorithms as flexible as possible, there are good reasons not to require that iterators know their container.
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  10. #10
    Registered User
    Join Date
    Feb 2006
    Posts
    312
    it removes an element from the container, it just doesn't destroy the element. remove() returns an iterator to the element, so you can either pass that iterator to erase(), or store it for later use.

  11. #11
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> it removes an element from the container, it just doesn't destroy the element.

    That sentence is misleading. If it removed the element(s) from the container, then if you check size() after the call to remove it would be different, but it is not. It does not actually remove elements from the container or destroy them, it simply manipulates the contents of the container so that you can actually remove those items if you choose to do so.

  12. #12
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Trying to erase an element from a vector.
    Use a list. A list is just as easy to use as a vector, and removing elements is very efficient. With a list when you remove() the element, it is gone. Your code traverses over your entire vector, so it doesn't look like you need random access, i.e. being able to use myVector[i]. If the word 'list' is too scary for you, just squint your eyes and pretend a list is a vector.

    Also, when you use loops to traverse an STL container, you do it like this:
    Code:
    list<int> myList;
    myList.push_back(10);
    myList.push_back(20);
    myList.push_back(30);
    
    list<int>::iterator pos;
    for(pos = myList.begin(); pos != myList.end(); ++pos)
    {
    	cout<<*pos<<endl;
    }
    You can also use the predefined find() function to search an STL container for something:
    Code:
    #pragma warning( disable : 4786 )
    #include <iostream>
    #include <string>
    #include <list>
    #include <algorithm> //find()
    
    using namespace std;
    
    int main() 
    {	
    
    	list<string> myList;
    	myList.push_back("Joe");
    	myList.push_back("Mary");
    	myList.push_back("Tim");
    
    	string name = "Mary";
    	list<string>::iterator result;
    	
    	result = find(myList.begin(), myList.end(), name);
    	
    	if(result != myList.end())
    	{
    		cout<<*result<<endl;
    	}
    	else
    	{
    		cout<<"Name not found."<<endl;
    	}
    
    	myList.remove("Mary");
    	
    	result = find(myList.begin(), myList.end(), name);
    	
    	if(result != myList.end())
    	{
    		cout<<*result<<endl;
    	}
    	else
    	{
    		cout<<"Name not found."<<endl;
    	}
    
        return 0;
    }
    Last edited by 7stud; 03-26-2006 at 04:32 PM.

  13. #13
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Quote Originally Posted by 7stud
    Use a list. A list is just as easy to use as a vector, and removing elements is very efficient. With a list when you remove() the element, it is gone.
    using std::remove() on an std::list won't use that advantage, it will be as slow as with an std::vector.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  14. #14
    Registered User
    Join Date
    Feb 2006
    Posts
    312
    Quote Originally Posted by Daved
    That sentence is misleading. If it removed the element(s) from the container, then if you check size() after the call to remove it would be different, but it is not. It does not actually remove elements from the container or destroy them, it simply manipulates the contents of the container so that you can actually remove those items if you choose to do so.
    My bad then For some reason I thought it changed the ordering of the container, ajoining the 2 elements either side of the one to be erased.

  15. #15
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You're right, it does change the ordering. The "removed" elements are moved to the end so that if you do call erase with the returned iterator, the end will be chopped off. If you don't call the erase, though, the container still contains the removed elements, they are just after all the others.

    >> using std::remove() on an std::list won't use that advantage, it will be as slow as with an std::vector.

    Which is why you should use the list member function remove() instead of the generic algorithm if you do switch to lists.

    A deque is another option, but a set (or unordered_set) might be best if you actually were worried about performance and you are doing a lot of lookups and removes.

Popular pages Recent additions subscribe to a feed