Vectors

This is a discussion on Vectors within the C++ Programming forums, part of the General Programming Boards category; I read cprogramming.com's tutorial on the vector class, and I understand how they work. However, I encountered yet another problem ...

  1. #1
    Registered User
    Join Date
    Nov 2004
    Posts
    25

    Lightbulb Vectors

    I read cprogramming.com's tutorial on the vector class, and I understand how they work. However, I encountered yet another problem while programming a console based address book.

    I want the user to be able to delete a contact from a vector of contacts, and (obviously) specify which contact to delete.

    I know there is a clear() function already provided to the vector class, and I was wondering if there is any way to delete specific elements of the vector using the [] operators?

    I'm really confused on how to accomplish this, so any help would be appreciated. I don't want to post an entire program here get an answer to a simple question, so if anyone wants/needs to see the code, contact me.

    Also, is there a function provided for sorting the vector in any way? If not it's no big deal because I'm pretty sure I could write one for my needs, but it would be handy to have a reference. (I've only glanced over basic sorting algorithms, such as bubble sort and all that.)

    Ever since I registered for this board and started using it (like two days ago) I've been making tremendous progress towards my programming education. ^^ I thank you all. This project has been a great learning experience so far.

    Thankee. =)
    Last edited by Callith; 11-26-2004 at 01:00 PM.

  2. #2
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    There is an erase function which takes an iterator (or pair of them -- start and end): http://cppreference.com/cppvector_details.html#erase

    There is also a sort method in <algorithm>. http://www.sgi.com/tech/stl/sort.html
    It takes a begining and ending iterator (vec.begin() and vec.end() for example), and a weak ordering relation (basically some sort of 'less than operator'). The type if a function object (something derived from binary_function of which an example is here: http://www.sgi.com/tech/stl/binary_function.html )

    If any of that seems incomprehensible (which it certainly can be) just post here and I (or someone else can help.

    Cheers
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  3. #3
    Registered User big146's Avatar
    Join Date
    Apr 2003
    Posts
    74
    Vectors provide no operation to remove elements directly that have a certain value.You must use an algorithm to do this.
    Take a look at this and it might clear things up a little for ya.
    Code:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    int main()
    {
    	vector<char> v;
    	int i;
    
    	for( i = 0; i <= 24; ++i )
    		v.push_back(i + 'A' );
    
    	cout << "Contents of v is: " << endl;
    	for( i = 0; i < v.size(); ++i )
    		cout << v[i];
    	cout << endl;
    
    	vector<char>::iterator p;
    	p = find( v.begin(), v.end(), 'G' );
    
    	if(p != v.end() )
    		v.erase(p);
    
    	for(i = 0; i < v.size(); ++i )
    		cout << v[i];
    	cout << endl;
    }
    big146

  4. #4
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,803
    There are other containers that can provide you with all that you seek to do. A set or multiset container for instance will allow you to erase specific elements using either an iterator or a copy of the element you wish to search for. It will also automatically sort the elements you add to it, provided you tell it how the elements should be ordered by implementing the less-than operator. A set will only store unique elements while a multiset can be used to store many elements with the same value. As an example:

    Code:
    #include <iostream>
    #include <iterator>
    #include <algorithm>
    #include <string>
    #include <set>
    
    class person
    {
    public:
        std::string name;
    
        // Constructors
        person() {}
        person(const std::string& rhs) { name = rhs; }
    
        // Friend operators
        friend bool operator<(const person& lhs, const person& rhs);
        friend std::ostream& operator<<(std::ostream& os,const person& rhs);
    };
    
    //Friend insertion operator, needed to make "copy" work properly
    std::ostream& operator<<(std::ostream& os,const person& rhs)
    {
        return os << rhs.name;
    }
    
    //Friend less-than operator, needed to make "erase" and
    //automatic sorting work properly
    bool operator<(const person& lhs, const person& rhs)
    {
        return lhs.name < rhs.name;
    }
    
    
    int main()
    {
        std::set<person> strSet;
    
        strSet.insert(person("Robert"));
        strSet.insert(person("Johnson"));
        strSet.insert(person("Albert"));
    
        std::cout << "Before erasing Johnson: ";
        std::copy(strSet.begin(),strSet.end(),
                  std::ostream_iterator<person>(std::cout," "));
    
        // Provide a copy of element "Johnson" to the erase function
        strSet.erase(person("Johnson"));
    
        std::cout << "\nAfter erasing Johnson : ";
        std::copy(strSet.begin(),strSet.end(),
                  std::ostream_iterator<person>(std::cout," "));
        std::cout << std::endl;
    
        return 0;
    }
    This should output:

    Code:
    Before erasing Johnson: Albert Johnson Robert
    After erasing Johnson : Albert Robert
    As you can see, even though the elements were inserted in reverse alphabetical order, the set container automatically sorted them properly because that is how I implemented the less-than operator in this case.

    If it looks like the copy function and overloading of the insertion operator is too confusing for you, they can be removed and a more conventional looping mechanism can be used to output the contents of the set container to the screen... but you do need the less-than operator to define how the elements are to be sorted.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  5. #5
    Registered User manofsteel972's Avatar
    Join Date
    Mar 2004
    Posts
    317
    A simple way to delete an item from a vector is to swap it with the last element then pop_back() to remove the last element
    "Knowledge is proud that she knows so much; Wisdom is humble that she knows no more."
    -- Cowper

    Operating Systems=Slackware Linux 9.1,Windows 98/Xp
    Compilers=gcc 3.2.3, Visual C++ 6.0, DevC++(Mingw)

    You may teach a person from now until doom's day, but that person will only know what he learns himself.

    Now I know what doesn't work.

    A problem is understood by solving it, not by pondering it.

    For a bit of humor check out xkcd web comic http://xkcd.com/235/

  6. #6
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Also in vectors do NOT erase() the first element of the vector. If the vector has an odd number of members there is a specific way you must erase them. I've encountered this in my recent project and it is quite annoying.

  7. #7
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Bubba
    Also in vectors do NOT erase() the first element of the vector. If the vector has an odd number of members there is a specific way you must erase them. I've encountered this in my recent project and it is quite annoying.
    Hmmm, you mean this doesn't work?
    It should:
    Code:
    vec.erase(vec.begin(),vec.begin()+1);
    //or
    vec.erase(vec.begin());
    Last edited by Sang-drax; 11-27-2004 at 09:04 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  8. #8
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    It does except that any future access to the vector will crash the program.

  9. #9
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    This seems to run fine. MSVC 6.0 professional edition:
    Code:
    #include <vector>
    #include <iostream>
     
    int main()
    {
       std::vector<int> x(5);
       x.erase(x.begin());
     
       x[0] = 2;
       for(std::vector<int>::iterator it = x.begin(); it != x.end(); ++it)
    	 std::cout << *it;
     
       std::cin.get();
       return 0;
    }
    Perhaps it was just a bug in your compiler Bubba? I really can't imagine the standard requiring different deletion methods for odd an even sized vectors.
    Last edited by Hunter2; 11-27-2004 at 07:46 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  10. #10
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Hmm. Shakti and I have come across the bug. I thought it was stupid that the vector implementation did not account for this housekeeping issue. Perhaps it is a bug in my code.

    I'll post and let you see for yourself. For some reason I cannot delete the first laser object in the vector - future firing of lasers and thus adding a laser to the vector CTD's the entire game.
    Code:
    void Update(D3DXVECTOR3 &_ObjectVector,D3DXMATRIX view,float timeDelta)
        {
               
          //D3DXMATRIX proj;
          //Device->GetTransform(D3DTS_PROJECTION,&proj);
    
          std::vector<CLaser>::iterator laser;
          LasersDrawn=0;
          for (laser=Lasers.begin();laser!=Lasers.end();laser++)
          {
            
    
            //D3DXMATRIX InvView;
            //D3DXMatrixInverse(&InvView,0,&view);
    
            
            if (laser->Properties.LifeTimer>laser->Properties.LifeDistance)
            {
              if (laser!=Lasers.end())
              {
                laser=Lasers.erase(laser);
                NumLasers--;
              }
              
            } 
            if (laser!=(Lasers.end()))
            {
                  LasersDrawn++;
                  laser->Properties.LifeTimer+=timeDelta;
                  laser->Properties.Position+=
                    (laser->Properties.VelocityVector*laser->Properties.Speed)*timeDelta;
                  Render(timeDelta,view,laser);
            }
    As you can see I'm constantly checking for the end of the vector yet this loop should never ever get there. If you could help I would be greatly indebted to you as this bug is annoying me. The code right now looks like crap but I had to code it this way or the thing crashed.

  11. #11
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Actually in order not to hijack this thread could you discuss the solution over in my new screenshots thread on the game programming board.

    Or if you think it will add to others understanding of vectors perhaps it would be appropriate to post it here. Your decision.

  12. #12
    Registered User
    Join Date
    Nov 2004
    Posts
    25

    Thumbs down Another problem.

    Well, infact I have another question.
    I worked on the code abit more and wrote everything, but it won't compile now. I looked at a few examples and checked out a few more reference sites and vector tutorials, but I think it has to do with member functions returning a value. I'm not sure though. My program won't compile.

    It's a syntax error inside of list::list *deleteContact()

    I was hoping someone could take a look at it and tell me what I did wrong.

    The line that gives me the error is:
    contactList=(contactList[(contactNo-1)].contactDelete(contactList);

    contactList is a protected data member of list of type vector<contact>, which gets the new value of the new contactList after deleteing a contact.

    Maybe someone could look at my program and tell me why it doesn't succesfuly compile? I've tried everything I can think of to fix the compile error. =(

    Code:
    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    class contact{
        protected:
            string validField[4];
            string cFirstName;
            string cLastName;
            string cEmail;
            string cPhoneNumber;
    	    int contactNo;
        public:
            contact(string *firstName, string *lastName){
                cFirstName=(*firstName);
                cLastName=(*lastName);
                cEmail="Unknown";
                cPhoneNumber="Unknown";
                
                validField[0]="First Name";
                validField[1]="Last Name";
                validField[2]="E-Mail";
                validField[3]="Phone Number";
            }
            void quickDisplay(){
                cout<<cLastName<<", "<<cFirstName<<endl;
                return;
            }
            string firstName(){
                return (cFirstName);
            }    
            void edit(){
                int select;
                string newValue;
                for (int i=0;i<4;++i){
                    cout<<(i+1)<<". "<<validField[i]<<endl;
                }
                cout<<"Which field would you like to edit (1-4, 0 aborts): ";
                cin>>select;
                cout<<endl;
                if (!(select>=1&&select<=4)){
                    cout<<"Invalid choice. Aborting edit.";
                    return;
                }
                cout<<"Enter new "<<validField[(select-1)]<<" for "<<cFirstName<<": ";
                cin>>newValue;
                
                switch (select){
                    case 1:
                        cFirstName=newValue;
                        break;
                    case 2:
                        cLastName=newValue;
                        break;
                    case 3:
                        cEmail=newValue;
                        break;
                    case 4:
                        cPhoneNumber=newValue;
                        break;
                    default:
                        cout<<"Error: Selection does not represeent valid field..."<<endl;
                        return;
                        break;
                }
                return;
            }
            vector<contact> *contactDelete(vector<contact> loadedContactList){
                vector<contact>::iterator matchingContact;
                for (matchingContact=(loadedContactList.begin());(matchingContact)<=(loadedContactList.end());++matchingContact){
                    if ((matchingContact->contactNo)==(this->contactNo)){
                        loadedContactList.erase(matchingContact);
                    }
                }
                return (&loadedContactList);
    	    }
                
            void view(){
                cout<<validField[0]<<": "<<cFirstName<<endl;
                cout<<validField[1]<<": "<<cLastName<<endl;
                cout<<validField[2]<<": "<<cEmail<<endl;
                cout<<validField[3]<<": "<<cPhoneNumber<<endl;
                return;
            }
    };
        
    class list{
        public:
            list(string *newListName){
                listName=(*newListName);
                loaded=true; // If there's an instance, it's been loaded.
            }
            vector<contact> loadedContactList(){
                return (contactList);
            }
            void unload(){
                loaded=false;
                return;
            }
            void view(){
                cout<<endl
                    <<"Contact List: "<<listName<<endl;
                for (int i=0;i<(contactList.size());++i){
                    cout<<(i+1)<<". ";
                    contactList[i].quickDisplay();
                }
                
                cout<<"Blank"<<endl; //Instructions for viewing a specific contact in detail goes here    
                
                return;
            }
            inline bool loadCheck(){
                if (loaded==false){
                    cout<<"Please [l]oad or [c]reate a list first..."<<endl;
                    return (false);
                }
                return (true);
            }    
            list *createContact(){
                if (!loadCheck()){
                    return (this);
                }
                string firstName;
                string lastName;
                cout<<"Please enter the new contact's first name: ";
                cin>>firstName;
                cout<<endl;
                cout<<"Please enter the new contact's last name: ";
                cin>>lastName;
                cout<<endl;
                contact newContact(&firstName, &lastName);
                contactList.push_back(newContact);
                cout<<"Your new contact has been successfully created."<<endl;
                return (this);
            }
            list *editContact(){
                if (!loadCheck()){
                    return (this);
                }
                int contactNo;
                view();
                cout<<"Which contact would you like to edit? (1-"<<(contactList.size())<<", 0 aborts): ";
                cin>>contactNo;
                cout<<endl;
                if ((contactNo<=0)||(contactNo>contactList.size())){
                    cout<<"Editing Aborted."<<endl;
                    return (this);
                }
                
                cout<<"Editing "
                    <<(contactList[(contactNo-1)].firstName())<<endl;    
                contactList[(contactNo-1)].edit();
                cout<<"Field successfully changed."<<endl;
                return (this);
            }
            void viewContact(){
                if (!loadCheck()){
                    return;
                }
                int contactNo;
                view();
                cout<<"Which contact would you like to view? (1-"<<(contactList.size())<<", 0 aborts): ";
                cin>>contactNo;
                cout<<endl;
                if ((contactNo<=0)||(contactNo>contactList.size())){
                    cout<<"Viewing Aborted."<<endl;
                    return;
                }
                cout<<"Now viewing "
                    <<(contactList[(contactNo-1)].firstName())<<endl;
                contactList[(contactNo-1)].view();
                return;
            }
            list *deleteContact(){
                if (!loadCheck()){
                    return (this);
                }
                int contactNo;
                view();
                cout<<"Which contact would you like to delete? (1-"<<(contactList.size())<<", 0 aborts): ";
                cin>>contactNo;
                cout<<endl;
                if ((contactNo<=0)||(contactNo>contactList.size())){
                    cout<<"Deletion aborted."<<endl;
                    return (this); //Note: I might need to return the new contact list to loadedList for the filestreams to work correctly
                }
                char confirm;
                cout<<"Are you sure who want to delete "
                    <<(contactList[(contactNo-1)].firstName())
                    <<"? (All details will be lost upon saving.) [Y/N]: ";
                cin>>confirm;
    	        if (confirm=='y'||confirm=='Y'){
                    contactList=(contactList[(contactNo-1)].contactDelete(contactList);
                    cout<<"Deletion successful. Remember to save.";
                }
                else cout<<"Deletion aborted."<<endl;
                return (this);
            }            
        protected:
            bool loaded;
            string listName;
            vector<contact> contactList;
    };
        
    //Prototypes
    void commandLine();
    list createNewList();
    
    int main(){
        cout<<"Welcome to the console based Contact Manager."<<endl
            <<"Input 'h' at the '->' for help."<<endl<<endl;
        
        commandLine();
        
        return (0);
    }
    
    void commandLine(){
        char command;
        string blankString;
        
        list loadedList(&blankString); //Creates a blank list
        loadedList.unload(); //blank list does not count as a loaded list
    
        do{
            cout<<endl;
            cout<<"-> ";
            cin>>command;
            cout<<endl;
            
            switch (command){
                case 'h':
                case 'H':
                    cout<<"Issue a command by inputting the coresposnding"<<endl
                        <<"letter in brackets at the command line. [->]"<<endl
                        <<endl
                        <<"[H]elp"<<endl
                        <<"[Q]uit"<<endl
                        <<"[C]reate New Contact List"<<endl
                        <<"[L]oad Contact List"<<endl
                        <<"V[i]ew Contact List"<<endl
                        <<"[S]ave Contact List"<<endl
                        <<"[D]elete Contact List"<<endl
                        <<"Create [N]ew Contact"<<endl
                        <<"[E]dit Contact Details"<<endl
                        <<"[V]iew Contact Details"<<endl
                        <<"Dele[t]e Contact"<<endl
                        <<endl;
                    break;
                case 'q':
                case 'Q':
                    cout<<"Are you sure you want to quit? [Y/N]: ";
                    cin>>command;
                    cout<<endl;
                    if (command=='Y'||command=='y'){
                        return;
                    }
                    break;
                case 'c':
                case 'C':
                    char confirm;
                    cout<<endl
                        <<"Are you sure? Make sure to save the current list. [Y/N]: ";
                    cin>>confirm;
                    cout<<endl;
                    if (confirm=='y'||confirm=='Y'){
                        loadedList=createNewList();
                        cout<<"Your new list has been created and loaded."<<endl;
                    }
                    break;
                case 'i':
                case 'I':
                    loadedList.view();
                    break;
                case 'n':
                case 'N':
                    loadedList=(*(loadedList.createContact())); //changes are made to list here
                    break;
                case 'e':
                case 'E':
                    loadedList=(*(loadedList.editContact())); //and here
                    break;
                case 'v':
                case 'V':
                    loadedList.viewContact();
                    break;
                case 't':
                case 'T':
                    loadedList=(*(loadedList.deleteContact())); // and here. They all should return value of (&this).
                    break;
                default:
                    cout<<"That is an invalid command. Input 'h' for help."<<endl;
                    break;
            };        
        }
        while(true);
        return;
    }
    
    list createNewList(){
        string newListName;
        
        cout<<"Please input a name for the new list: ";
        cin>>newListName;
        
        list newList(&newListName);
        
        return (newList);
    }
    Thanks.
    Callith

    PS I'm new at both programming and posting on this message board. If that was too much code (which I think it was) don't hesitate to tell me. I don't want to be an annoyance.
    Last edited by Callith; 11-28-2004 at 09:51 AM.

  13. #13
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    Better too much code/detail than not enough.
    In this case, though, I didn't need to look at any of your code. Count the number of opening parentheses and closing parentheses in this line.
    Code:
    contactList=(contactList[(contactNo-1)].contactDelete(contactList);
    Cheers
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  14. #14
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Bubba:
    Code:
    if (laser->Properties.LifeTimer>laser->Properties.LifeDistance)
    {
    if (laser!=Lasers.end())
    {
    This just seems somewhat odd, since you're checking if the iterator is valid AFTER you've already dereferenced it, but I assume that you're already aware of this. [snip]*see edit*[/snip]

    **EDIT**
    Hm, on second thought, from what I see in your code, every time you delete a laser, the iterator will skip the next laser: You delete the laser, assign the iterator to the next laser, and then you hit the end of the loop and the iterator increments again; thus you've skipped the laser in between. So if you have an odd number of iterators:

    0) You have 3 elements
    1) Delete element 0, iterator now points to element 0 (previously element 1)
    2) Do something with element 0, increment iterator; now points to element 1 (formerly 2)
    0b) You now have 2 elements, iterator points to element 1 (last)
    1b) Delete this element, iterator now points to end
    2b) If iterator != end, do nothing; increment iterator; now points 1 beyond end
    0c) You now have 1 element, iterator points beyond the end of the sequence (still != end).
    1c) Try to dereference it, and BOOM! kablooey, your loop crashes.

    One quick solution I can think of is, stick it in a while loop and do the iterator management by hand (if you erase an element, don't increment iterator).
    Last edited by Hunter2; 11-28-2004 at 06:30 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  15. #15
    Registered User
    Join Date
    Nov 2004
    Posts
    25
    Thanks for pointing that out Zach, but it just went back to the error I had before. There's no match for operator=, which I thought (for vectors,) just replaced one vector with the new one. SHouldn't the last part technically be the value of a vector?

    I'm confused.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Vectors
    By naseerhaider in forum C++ Programming
    Replies: 11
    Last Post: 05-09-2008, 08:21 AM
  2. How can i made vectors measuring program in DevC++
    By flame82 in forum C Programming
    Replies: 1
    Last Post: 05-07-2008, 02:05 PM
  3. How properly get data out of vectors of templates?
    By 6tr6tr in forum C++ Programming
    Replies: 4
    Last Post: 04-15-2008, 10:35 AM
  4. How to use Vector's in C++ !?!
    By IndioDoido in forum C++ Programming
    Replies: 3
    Last Post: 10-14-2007, 11:13 AM
  5. Points, vectors, matrices
    By subnet_rx in forum Game Programming
    Replies: 17
    Last Post: 01-11-2002, 01:29 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21