Thread: runtime error with vector

  1. #1
    Registered User
    Join Date
    Jul 2008
    Posts
    34

    runtime error with vector

    When i run my code and type in a number into a variable and then check my vector to see if that number is present and if so delete it. However i keep getting an error with this segment of code spedifically the if statement.

    Code:
    	cin >> Age;
    	
    	for(unsigned int i=0;i<=(names.size());i++)
    	{
    		if(names[i]==Age)
    		{
    			names.erase((names.begin() + i));
    			break;
    		}
    	}
    The vector has the numbers 1,2,3,4 inside and when i run the code if i enter 2i get a runtime error saying the vector subscript is out of range? any ideas?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Do you also get the error if you do i < names.size() instead?

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Consider using at() instead of operator[] for vector access by index. That way you're guaranteed that an exception is thrown so that if you make such mistakes later they will be more obvious. Using operator[] like that means anything can happen if you overstep the bounds of the vector.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I see little benefit in using at() since it obviously has more overhead. When an out of bounds vector access is performed it is very clear to the programmer what happened. The error message is not vague and the error is easy to fix. The OP even says that the error is 'vector subscript out of range'. That's a very clear error and much clearer than usual for any template-based error. Proper use of the vector is the problem here and not so much the use of the array access operator.

  5. #5
    Registered User
    Join Date
    Jun 2007
    Posts
    219
    Its beter to use the at() method cause [] operetor inserts null or the value provided on the specefied index if it doesnt exist. so for reading purpouse using at(0 is recomended.
    However while using you should use vector Iterators.
    I am assuming that Age is string and names is vector of strings too.

    Code:
    vector<string>::iterator it;
    cin>>age;
    for(it=names.begin();it < names.end();it++){
      if(*it == age){
        names.erase(it);
      }
    }
    if names is an int vector not a strings vector use atoi() on age to convert it to int

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    No, operator [] does not insert for vector.
    Using operator [] for an index that does not exist results in undefined behavior.
    Unfortunately, there's no way to use an .at() function that return false or fails silently if it fails instead of throwing.
    Otherwise I would always use some kind of assert or safe function; otherwise we're just back to plain old unsafe C.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Jun 2007
    Posts
    219
    Quote Originally Posted by Elysia View Post
    No, operator [] does not insert for vector
    Nope It does Insert an element on that Position if doesnt exist. I am not asking you to belief my words just compile this Program and see its output.
    http://pastebin.com/f77cf1921
    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
    
    using std::cout;
    using std::endl;
    using std::vector;
    
    int main(int argc, char** argv){
            vector<int> v;
            v.push_back(5);
            v.push_back(10);
            cout<<"Inserting"<<endl;
            cout<<v[0]<<endl<<v[1]<<endl<<v[2]<<endl<<v[3]<<endl;
            return EXIT_SUCCESS;
    }
    Quote Originally Posted by Elysia View Post
    Using operator [] for an index that does not exist results in undefined behavior.
    Its not UNDEFINED behaviour the behaviour is well defined that it will insert an element on that index
    Quote Originally Posted by Elysia View Post
    Unfortunately, there's no way to use an .at() function that return false or fails silently if it fails instead of throwing.
    So ? Whats wrong with Exceptions ?? I think try catch block is more sturctured than returning false and something like that.
    and at() returns an element so if it returns false or 0x0 or 0 or -1 or null
    WOULDNT YOU THINK THAT THIS IS THE VALUE IN THAT POSITION

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    However while using you should use vector Iterators.
    Unfortunately your example is wrong... Erase invalidates the iterator you are using to iterate the loop.
    Therefore, if possible you should look into using the standard algorithms . Your example could be corrected as:
    Code:
    //remove all items that are equal to age
    names.erase(remove(names.begin(), names.end(), age), names.end());
    And OP's example could be corrected to:
    Code:
    //erase the first occurrence of age
    names.erase(find(names.begin(), names.end(), age));
    And if you want/need to write manual loops, you should simply remember that in idiomatic C++ all ranges are up to but not including the last index. Therefore you should practically never need the <= operator to loop over a range (use <, or more generally !=).

    Its not UNDEFINED behaviour the behaviour is well defined that it will insert an element on that index
    Definitely undefined with vector.

    (Although I'm not too happy about at(): 99.99&#37; of use cases the range check is completely redundant - once the code is not giving you any troubles.)
    Last edited by anon; 07-15-2008 at 09:49 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Registered User
    Join Date
    Jun 2007
    Posts
    219
    Quote Originally Posted by anon View Post
    Unfortunately your example is wrong... Erase invalidates the iterator you are using to iterate the loop.
    Therefore, if possible you should look into using the standard algorithms .
    So what ? It erases the entry thats age matches with the value.what he will do with that iterator after erasing the thing is not a part of the example.
    that example Compiles and run.
    http://pastebin.com/f306d7d4a
    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <string>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::vector;
    using std::string;
    
    int main(int argc, char** argv){
            vector<string> names;
            names.push_back("5");
            names.push_back("10");
            names.push_back("15");
            string age;
            vector<string>::iterator it;
            cin>>age;
            for(it=names.begin();it < names.end();it++){
              if(*it == age){
                names.erase(it);
              }
            }
            for(it=names.begin();it<names.end();it++){
              cout<<*it<<endl;
            }
            return EXIT_SUCCESS;
    }
    Quote Originally Posted by anon View Post
    Therefore you should practically never need the <= operator to loop over a range (use <, or more generally !=
    using < and != doesnt make any difference and its personal favoures of people and it varies man to man and there is nothing impratical or wrong or bad in any of this <= or < or != untill it matches the algorithm.

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Sorry but your example is slightly wrong. Try this small modification and input 5. It should remove all 5-s, shouldn't it? But it doesn't! After each erasure you skip one item - and if you skip the last you may well increment names.end() and enter undefined land.

    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <string>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::vector;
    using std::string;
    
    int main(int argc, char** argv){
            vector<string> names;
            names.push_back("5");
            names.push_back("5");
            names.push_back("15");
            string age;
            vector<string>::iterator it;
            cin>>age;
            for(it=names.begin();it < names.end();it++){
              if(*it == age){
                names.erase(it);
              }
            }
            for(it=names.begin();it<names.end();it++){
              cout<<*it<<endl;
            }
            return EXIT_SUCCESS;
    }
    For your information, undefined behaviour doesn't mean that the program will crash or do otherwise an obviously wrong thing. Undefined behaviour means that your program may appear to work correctly - until the slightest change in any unrelated part of the program. You may get away with out-of-bound accesses unpunished, for example because the vector overallocates and that memory still belongs to it, although it is unused.

    That is, you have to know what you are doing.

    As to whether [] inserts for vector, would it be that hard to find out:
    Code:
    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<int> v;
        v.reserve(2);
        v[0] = 10;
        std::cout << v.size();
    }
    This should print (at least) 1 according to your theory, but the vector nevertheless reports that it contains 0 items. This code just accesses an item out of the vector's bounds (and it probably gets away with it, since that memory is reserved - not making this code correct, though).

    As to correcting your erase example, try this:
    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <string>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::vector;
    using std::string;
    
    int main(int argc, char** argv){
            vector<string> names;
            names.push_back("5");
            names.push_back("5");
            names.push_back("15");
            string age;
            vector<string>::iterator it;
            cin>>age;
    
            for(it=names.begin();it < names.end();){
              if(*it == age){
                it = names.erase(it);
              }
              else {
                ++it;
              }
            }
    
            for(it=names.begin();it<names.end();it++){
              cout<<*it<<endl;
            }
            return EXIT_SUCCESS;
    }
    As you can see the loop is not as trivial as that. Therefore it is a better idea to use std algorithms for such tasks (particularly since the erase-remove combo has better complexity and does a lot less copying for larger datasets).
    Last edited by anon; 07-15-2008 at 10:34 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  11. #11
    Registered User
    Join Date
    Jun 2007
    Posts
    219
    input 5. It should remove all 5-s, shouldn't it? But it doesn't!
    according to the original Code from te5la which uses break means he want to remove the first only so It doesnt need to care about all other matches.
    operator[] will insert an item if that position is blank

    http://pastebin.com/f6f987ea4
    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
     
    using std::cout;
    using std::endl;
    using std::vector;
     
    int main(int argc, char** argv){
            vector<int> v;
            v.push_back(5);
            v.push_back(10);
            cout<<"Inserting"<<endl;
            cout<<v[0]<<endl<<v[1]<<endl<<v[2]<<endl<<v[3]<<endl<<v[4]<<endl;
            cout<<"Printing"<<endl;
            cout<<v[4]<<endl;//v[4] has a value and its being printed which means [] operator has inserted it
            return EXIT_SUCCESS;
    }
    Run the above program and see that when I am just calling v[2], v[3], v[4] Its inserting null/junk values in it.and while doing cout<<v[4] Its showing up that too.

  12. #12
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by noobcpp View Post
    Nope It does Insert an element on that Position if doesnt exist. I am not asking you to belief my words just compile this Program and see its output.
    It does no such thing. And the output of your program is irrelevant. The behavior is UNDEFINED, meaning anything could happen, including appearing to work correctly.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  13. #13
    Registered User
    Join Date
    Jun 2007
    Posts
    219
    But in 99&#37; cases it does insert.
    doesnt matter it inserts or not doesnt its behaviour is undefined ort not. when one is only accessing values one should use at() instead of using operator[] cause operator[] is used both for get and set operation and at() is used only for get operation so its beter to limit the scope to only get values and use at()

  14. #14
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    You cannot be a good C/C++ programmer if you have an inability to accept it when you find out something results in undefined behavior.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by noobcpp View Post
    But in 99&#37; cases it does insert.
    doesnt matter it inserts or not doesnt its behaviour is undefined ort not. when one is only accessing values one should use at() instead of using operator[] cause operator[] is used both for get and set operation and at() is used only for get operation so its beter to limit the scope to only get values and use at()
    Is it so hard to get it into your thick skull?
    OPERATOR [] DOES NOT INSERT ANYTHING.
    What you is random junk (aka, undefined behavior!).
    It's the same as doing:

    Code:
    int myarray[2];
    cout << myarray[3] << endl;
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. can some one please tell me the cause of the error ?
    By broli86 in forum C Programming
    Replies: 8
    Last Post: 06-26-2008, 08:36 PM
  2. syntax help?
    By scoobygoo in forum C++ Programming
    Replies: 1
    Last Post: 08-07-2007, 10:38 AM
  3. Vector class
    By Desolation in forum C++ Programming
    Replies: 2
    Last Post: 05-12-2007, 05:44 PM
  4. Need some help/advise for Public/Private classes
    By nirali35 in forum C++ Programming
    Replies: 8
    Last Post: 09-23-2006, 12:34 PM
  5. Certain functions
    By Lurker in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2003, 01:26 AM