c++ removing of line from a text file (need explanations) - c++

I am trying to remove a line containing username and password from text file.
so I tried to following,
1)Read the text file.
2)store the userName and password inside the textfile.
3)prompt the user which user he wants to delete.
4)the entire line will be deleted in the vector if the input matches with the username in the vector.
5)copy back to text file(not done yet)
I managed to get it by luck
textfile(userInfo.txt)
amber abc
janet def
chris DEF
gerald AZC
my output of my codes
Before Deletion
amber abc
janet def
chris DEF
gerald AZC
Enter User Name to delete: amber
After Deletion
janet def
chris DEF
gerald AZC
but what I don't really understand is, how my codes actually delete the entire line after it matches with my input espcially starting from
string name;
cout << "Enter User Name to delete: ";
cin >> name;
cout << " " << endl;
cout << "After Deletion" << endl;
for (int i =0; i<userDetails.size(); i++) {
if(userDetails[i].getUserName() == name){
userDetails.erase(userDetails.begin() + i);
}
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
}
I hope someone can explain it to me.
my codes
user.h
#ifndef user_user_h
#define user_user_h
#include <iostream>
class user {
public:
user() {
userName = " ";
password = " ";
}
user(std::string userName,std::string password);
std::string getUserName();
std::string getPassword();
void setUserName(std::string userName);
void setPassword(std::string password);
private:
std::string userName,password;
};
#endif
main.cpp
#include "user.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
user::user(string userName,string password) {
setUserName(userName);
setPassword(password);
};
string user::getUserName() {
return userName;
}
string user::getPassword() {
return password;
}
void user::setUserName(std::string userName) {
this->userName = userName;
}
void user::setPassword(std::string password) {
this->password = password;
}
int main(){
vector<user> userDetails;
string line;
string userName;
string password;
ifstream readFile("userInfo.txt");
while(getline(readFile,line)) {
stringstream iss(line);
iss >> userName >> password;
user userInfoDetails(userName,password);
userDetails.push_back(userInfoDetails);
}
readFile.close();
cout << "Before Deletion" << endl;
for (int i =0; i<userDetails.size(); i++) {
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
}
cout << " " << endl;
string name;
cout << "Enter User Name to delete: ";
cin >> name;
cout << " " << endl;
cout << "After Deletion" << endl;
for (int i =0; i<userDetails.size(); i++) {
if(userDetails[i].getUserName() == name){
userDetails.erase(userDetails.begin() + i);
}
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
}
}

I don't follow what you don't understand. However, I'm going to go over this snippet of code because it contains a serious bug that is common for beginners.
for (int i =0; i<userDetails.size(); i++) {
if(userDetails[i].getUserName() == name){
userDetails.erase(userDetails.begin() + i);
}
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
}
The reason this "works" is that when your program encounters an object in the vector whose username matches the inputted username, you erase it from the vector. When this happens, the index of every object in the vector that is "further to the right" of the erased object gets shifted down by one. So suppose the matching name is "amber" (index 0). On the first loop iteration, amber will be deleted; janet shifts to index 0; chris shifts to index 1; and gerald shifts to index 2. Still on the first loop iteration, it will output index 0 which is now chris so everything is fine. On all the remaining loop iterations, userDetails.size() will evaluate to the new post-delete size, 3, so you will only get 3 iterations total, for indices 0, 1, 2.
NOW FOR THE BUG: Try entering "gerald" as the name to delete.
If you do this, remember that it will get processed on the fourth iteration of the loop, when i is 3. Gerald will be deleted, reducing the size to 3 and the last valid index to 2. But i is still 3 at this point! So
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
on the fourth iteration is equivalent to:
cout << userDetails[3].getUserName() << " " << userDetails[3].getPassword() << "\n";
but there is no userDetails[3] and your program should segfault.
Here is how you would implement it properly:
for (int i =0; i<userDetails.size(); i++) {
if(userDetails[i].getUserName() == name){
userDetails.erase(userDetails.begin() + i);
continue; // skip to next iteration because we can't guarantee 'i' is a valid
// index or that username on this iteration doesn't match
}
cout << userDetails[i].getUserName() << " " << userDetails[i].getPassword() << "\n";
}
However, I prefer the following idiom:
auto i = userDetails.begin(), e = userDetails.end();
while (i != e)
{
if (name == i->getUserName())
{
i = userDetails.erase(i); // i is now equal to next element after deleted one
e = userDetails.end(); // update e to be equal to the new end
// don't output because we deleted
}
else
{
std::cout << i->getUserName() << ' ' << i->getPassword() << std::endl;
++i;
}
}

I'm not sure I understood what you didn't understand but I'll try to help...
You delete the line in the correct location.
You give the erase method an iterator which points at the element you want to delete.
When you do this, the next line gets the index of the deleted line and you print it (the previously next line which is now the line in index i).

It works because
userDetails.erase(userDetails.begin() + i);
deletes a user, which contains a username and a password.

Related

How do I print the number of words that begin with a certain character?

This is for an intro c++ class, the prompt reads:
Print the number of words that begin with a certain character. Let the user enter that character.
Although, I'm not sure how to do this.
Do I use parsing strings? I tried this because they inspect string data type but I kept getting errors so I took it out and changed it to characters. I want to learn how to do the "total_num" (total number of words that start with the letter the user chooses) and I also need some help with my for loop.
Example of desired output
user types in: a
outputs: "Found 1270 words that begin with a"
user types in: E
outputs: "Found 16 words that begin with E"
user types in: #
outputs: "Found 0 words that begin with #"
(I think I got this part down for non-alphabetical)
The data is from a file called dict.txt, it's a list of many words.
Here's a small sample of what it contains:
D
d
D.A.
dab
dabble
dachshund
dad
daddy
daffodil
dagger
daily
daintily
dainty
dairy
dairy cattle
dairy farm
daisy
dally
Dalmatian
dam
damage
damages
damaging
dame
My program:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
const int NUM_WORD = 21880;//amount of words in file
struct dictionary { string word; };
void load_file(dictionary blank_array[])
{
ifstream data_store;
data_store.open("dict.txt");
if (!data_store)
{
cout << "could not open file" << endl;
exit(0);
}
}
int main()
{
dictionary file_array[NUM_WORD];
char user_input;
int total_num = 0;
load_file(file_array);
cout << "Enter a character" << endl;
cin >> user_input;
if (!isalpha(user_input))
{
cout << "Found 0 that begin with " << user_input << endl;
return 0;
}
for (int counter = 0; counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]));
//toupper is used to make a case insensitive search
{
cout << "Found " << total_num << " that begin with " << user_input << endl;
//total_num needs to be the total number of words that start with that letter
}
}
}
There are a few things you can do to make your life simpler e.g. using a vector as the comment suggested.
Let's look at your for loop. There are some obvious syntax problems.
int main()
{
dictionary file_array[NUM_WORD];
char user_input;
int total_num = 0;
load_file(file_array);
cout << "Enter a character" << endl;
cin>>user_input;
if(!isalpha(user_input))
{
cout << "Found 0 that begin with " << user_input << endl;
return 0;
}
for(int counter = 0;counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]));
// ^no semi-colon here!
//toupper is used to make a case insensitive search
{
cout<< "Found " << total_num << " that begin with "<<
user_input << endl;
//total_num needs to be the total number of words that start with that letter
}
}//<<< needed to end the for loop
}
Let's get the for loop right. You want to count the matches in a loop and then report when you have finished the loop.
int total_num = 0;
//get character and file
for(int counter = 0;counter< NUM_WORD; counter++)
{
if (toupper(user_input) == toupper(file_array[counter].word[0]))
^^^no semi-colon here!
{
++total_num;
}
}
cout<< "Found " << total_num << " that begin with "<< user_input << endl;

On finding vowels and capitals char in the beginning of a string?

I've been making a little memory game as an exercise from a textbook I'm doing. It's called Grandma's trunk and it works by in one turn you found an item in the trunk and the next turn you say you found the previous item and the newest item on this turn...I think.
Mostly it's an exercise on using functions, which I think I've gotten down pretty well. But my output is completely wrong. I've believe I've located the problem in one function where I'm supposed to analyze the first character and decided if it needs an AN or A or THE before the string. There might be a problem with the random function I'm using to throw in predefined items from a small database. The int main() function is supposed to be relatively complete, this is just an exercise to master functions...which I, sorta? Would rather call it novice experience.
I thought that perhaps I was running into the getline bug where it couts a blank line, and from my understanding, is fixed by cin.ignore(); but all that did was force me to press enter twice when I enter data. Which...I sort of like. Perhaps I'm using gizmos like isupper and .at() wrong? I tried using find_first_of but it didn't really change anything.
output calling the storage trunk and the owner grandma and just using word1 word2 word3... wordn....as items found leaves me with the output.
In grandma trunk you've found a
and an ord3 word1.
it completely muddles up the output. I'm starting to think that the int main() body I was given wasn't exactly stellar. But I can't be 100% confident in my article function. Any help would just be incredible. I've been struggling using this among many books and advice from a buddy to teach myself a little about programming. It's been a rather huge headache.
program itself
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
using namespace std;
string CorrectArticle(string phrase);
string GetPhrase(void);
bool Continue(void);
string UpperCase(string);
string RandomItem(void);
const string PUNCTUATION = ".";
int main(){
//Variables
int turn;
bool flag;
string phrase,
article,
story, item,
storage, owner;
srand(time(NULL));
cout << "Welcome to Grandmother's Trunk 9000" << endl;
cout << "This is a memory game. Each turn a player" << endl;
cout << "Says an item to place inside a trunk. " << endl;
cout << "And the next player has to say what the " << endl;
cout << "previous player said plus his/her own item." << endl;
cout << "This will go around in revolving turns." << endl;
cout << endl << endl;
cout << "But Grandma's Trunk is a little dry..." << endl;
cout << "Let's change what the storage is and " << endl;
cout << "Who owns it." << endl << endl;
//define storage variable
cout << "What exactly is this storage?" << endl;
getline (cin, storage);
cout << "So the items are stored in " << storage << endl;
cout << endl;
//define owner
cout << "Who owns this " << storage << " ?" << endl;
getline (cin, owner);
cout << "The owner is " << owner << endl;
story = "In "+ owner + " " + storage + " you've found ";
turn = 0;
flag = Continue();
//While flag is true
while (flag) {
if (turn %2 == 0) {
item = GetPhrase();
} else {
item = RandomItem();
}
//set corrected item to article
article = CorrectArticle(item);
//advance the story every item
story = story + "\n and " + article + " " + item;
cout << story << PUNCTUATION << endl;
turn++;
flag = Continue();
}
return (0);
}
//Gives A, AN, and THE to correct words
// An if phrase starts with i,e,i,o,u or y
// A if phrase starts with other lower case letters
// The for phrases that start with an uppercase letter
string CorrectArticle(string phrase){
int i=0;
string correctedString;
string stringAn;
string stringA;
string stringThe;
stringAn= " an ";
stringA = " a ";
stringThe= "The ";
if (GetPhrase().at(i) = "a" or "e" or "i" or "u"){
correctedString = stringAn + GetPhrase();
}else if (isupper(GetPhrase().at(i))){
correctedString = stringThe + GetPhrase();
}else{
correctedString = stringA + GetPhrase();
}
return correctedString;
}
//This function takes no parameters
//and returns the user's input
string GetPhrase(void){
string itemInput;
cout << "\nWhat did you find? \n" << endl;
getline (cin, itemInput);
cout << "\nYou found " << itemInput << endl;
cin.ignore();
return itemInput;
}
//Asks user if they wish to continue
bool Continue(void){
//return false if no, true if yes
string continueString;
cout << "Would you like to continue?";
cout << " Yes or No would suffice" << endl;
getline(cin,continueString);
UpperCase(continueString);
cout << "You picked " << continueString;
if (UpperCase(continueString).find("NO") != string::npos){
return false;
} else if (UpperCase(continueString).find("YES") != string::npos){
return true;
}
}
//Changes the string to uppercase
string UpperCase(string stringUpper){
int i = 0;
while (i<stringUpper.size()){
stringUpper[i] = toupper(stringUpper[i]);
i++;
}
return stringUpper;
}
//Randomizes items found in game
string RandomItem(void){
int randomNumber;
int maxNumberOfItems = 5;
string randomizedItem;
randomNumber= rand() % maxNumberOfItems;
switch (randomNumber){
case 0:
randomizedItem = "Smaug";
break;
case 1:
randomizedItem = "Batman";
break;
case 2:
randomizedItem = "Yoda";
break;
case 3:
randomizedItem = "Paul Atreides";
break;
case 4:
randomizedItem = "Captain Kirk";
break;
default:
cout << "ERRORRRR! PANIC!" << endl;
}
return randomizedItem;
}
Remember that = is assignment, == for compare.
Also remember that you have to compare variable with value, such as:
if ((string == "a") or (string == "e") ...
If the or works for you, all the best. I've only been able to use ||. Must be compiler conformity issues.
Try this:
bool is_vowel(char letter)
{
const std::string vowels("aeiouAEIOU");
return (vowels.find_first(letter) != std::string::npos);
}
In other words, I place all the vowels in a string a search the string. If there is a match, the letter is a vowel.

Beginner's C++ program for a class

the assignment is the basic "cin a full name" and then "retrieve First Middle Last" bit, where you create a program that asks the user to type in their full first name into a single string and the programs picks apart the name and outputs it organized seperately. this is what i wrote:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
int index;
index = name.find(' ');
cin >> name;
cout << "First name: " << name.substr(0, index) << endl;
name = name.substr(index+1, name.length()-1);
index = name.find(' ');
cout << "Middle Name: " << name.substr(1, index) << endl;
name = name.substr(index+1, name.length()-1);
cout << "Last name: " << name;
return 0;
}
the code just wont seperate them right, and will not redefine 'name' correctly.
It always just bounces back to the beginning of the string.
any help for a newbie?
here's an example output:
Teenage Wonder Land
First name: Teenage
Middle Name: eenag
Last name: Teena
Process returned 0 (0x0) execution time : 7.942 s
Press any key to continue.
You wont' find anything before type your in console and sbustr should read from index 0
string name;
int index;
//index = name.find(' '); // comment out, name is empty, you won't find anything
cin >> name;
index = name.find(' '); // now you can find first space
cout << "Middle Name: " << name.substr(0, index) << endl;
// ^
Or just use std::stringstream
#include <sstream>
std::stringstream ss(name);
std::string token;
int i = 0;
while(ss >> token)
{
switch(i)
{
case 0:
std::cout << "First name: " << token << std::endl;
break;
case 1:
std::cout << "Middle name: " << token << std::endl;
break;
case 2:
std::cout << "Last name: " << token << std::endl;
break;
default:
break;
i++;
}
}
You clearly can't search for something in name before you assign it a value, which is what you're doing now:
string name;
int index;
index = name.find(' '); // No value assigned to name yet - nothing to search
cin >> name; // Now you're giving it a value (too late)
Instead, assign and then try to find a value:
string name;
int index;
cin >> name; // Assign a value first
index = name.find(' '); // Now try to find something in it
I think you should use std::getline to get the entire line of text at once. Currently you are only reading in the first word (>> operator will only extract text up to the next whitespace character).
std::string name;
if (std::getline(cin, name))
{
// extraction successful, "name" should contain entire line
}
Then, you can use one of the other answers in this question or continue with your own approach.
The extraction operator >> for istream will grab all non-whitespace characters in the buffer until it encounters a whispace.
So your input here:
Teenage Wonder Land
contains 3 whitespaces including the invisible newline at the end when you hit enter. From this you should be able to figure out what the following does:
cin >> name;
Hint: name doesn't contain the entire line you just entered.
#include <iostream>
#include <string>
using namespace std;
string getnext(const string &full, const string &delim, size_t &beg) {
size_t prev = beg;
beg = full.find(delim, beg);
if (beg != string::npos)
return full.substr(prev, beg-prev);
return full.substr(prev, full.length()-prev);
}
int main()
{
string name, temp, error = "NameError: Enter first, middle, last";
size_t index = 0;
getline(cin, name); //Get the full name
temp = getnext(name, " ", index); //Get first name
if (index == string::npos) {
cout << error;
return -1;
}
cout << "First name: " << temp << endl;
temp = getnext(name, " ", ++index); //Get middle name
if (index == string::npos) {
cout << error;
return -1;
}
cout << "Middle Name: " << temp << endl;
temp = getnext(name, " ", ++index); //Get last name
cout << "Last name: " << temp << endl;
return 0;
}

C++, Program ends before allowing input

To practice C++ I am trying to make a simple program that allows a user to input a name followed by a score and then allows the user to enter a name and get the score that name was entered with. The program works fine until I enter an escape character (ctrl + z) once I'm done entering names, after entering the escape character the program will output the line "Enter name of student to look up the score" but not allow the user to input the name and instead reads out "Press any key to exit". I'm totally stumped on how to fix this and any help is greatly appreciated.
#include "stdafx.h"
#include <std_lib_facilities.h>
int main()
{
vector <string>names;
vector <int>scores;
string n = " "; // name
int s = 0; // score
string student = " ";
cout << "Enter the name followed by the score. (Ex. John 89)" << endl;
while(cin >> n >> s)
{
for(size_t i = 0; i < names.size(); ++i)
{
if(n == names[i])
{
cout << "Error: Duplicate name, Overwriting" << endl;
names.erase(names.begin() + i);
scores.erase(scores.begin() + i);
}
}
names.push_back(n);
scores.push_back(s);
}
cout << "Name: Score:" << endl;
for(size_t j = 0; j < names.size(); ++j)
{
cout << names[j];
cout <<" " << scores[j] << endl;
}
cout << "Enter name of student to look up their score" << endl;
cin >> student;
for(size_t g = 0; g < names.size(); ++g)
{
if(student == names[g])
{
cout << "Score: " << scores[g] << endl;
}
}
keep_window_open();
return 0;
}
After you press the CTRL+Z key combination, which induces an EOF state to the cin stream, you need to bring the cin input stream back to its normal 'good' state to be able to use it again.
Add the following code after your for loop where you print the contents of the vectors.
cin.clear();
You may also check the state of the standard input stream using the rdstate() function. Anything other than 0 means that the standard stream is in an error state.
As has been said, you need to clear the error state on std::cin after reading the records failed.
std::cin.clear();
should do the trick. Here's my take on this using
proper data structures instead of two isolated vectors
const correctness
separating functions
no more hacky .erase() calls with magic indexes
#include <map>
#include <iostream>
std::map<std::string, int> read_records()
{
std::map<std::string, int> records;
std::string name;
int score;
std::cout << "Enter the name followed by the score. (Ex. John 89)" << std::endl;
while(std::cin >> name >> score)
{
if (records.find(name) != end(records))
{
std::cout << "Error: Duplicate name, Overwriting" << std::endl;
} else
{
records.insert({name, score});
}
}
std::cin.clear();
return records;
}
int main()
{
auto const records = read_records();
std::cout << "Name\tScore:" << std::endl;
for(auto& r : records)
std::cout << r.first << "\t" << r.second << std::endl;
std::cout << "Enter name of student to look up their score: " << std::flush;
std::string name;
if (std::cin >> name)
{
std::cout << "\nScore: " << records.at(name) << std::endl;
}
}
If you required contiguous storage, use a flat_map like the one from boost.

std::out_of_range at memory location 0x0043f7c4.. error when using vectors and an input file

What i am trying to do is get user to enter a key code and if it matches to display the information on the data input file. I am getting this error which i have no idea what for.
std::out_of_range at memory location 0x0043f7c4..
Below is my input file and my code
HEA,EMA,British Airways,030,025
HEA,EMA,Thomas Cook Airlines,020,040
HEA,DUB,British Airways,420,450
HEA,DUB,Thomas Cook Airlines,400,550
EMA,BAR,British Airways,120,140
EMA,BAR,Thomas Cook Airlines,100,150
ROM,EMA,British Airways, 120,125
ROM,EMA,Thomas Cook Airlines,150,090
ROM,BAR,British Airways,106,050
ROM,BAR,Thomas Cook Airlines,100,080
BAR,HEA,British Airways,125,090
BAR,HEA,Thomas Cook Airlines,100,120
DUB,EMA,Thomas Cook Airlines,450,380
DUB,EMA,Thomas Cook Airlines,420,450
below is my C++ code
#include <vector>
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
//#include "TravelFunctions.h"
using namespace std;
vector<string>flightDetails;
vector<string>flightSearch;
string airportDepart;
string airportArrive;
bool errorArrive = false;
bool errorDepart = false;
string timeTaken;
int tax;
int cost;
bool needtoentercodes = false;
string entry;
int main()
{
// first i will read in the airport.txt data and store the information into a vector.
ifstream flightdata("flightinfo.txt");
string flightnextline;
if (!flightdata)
{
cout << "Cannot Open the file 'flightdata.txt'";
}
else
{
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
}
cout << " ___________________ " << endl;
cout << "| Airport Key Code |" << endl;
cout << "|EMA = East Midlands|" << endl;
cout << "|HEA = Heathrow |" << endl;
cout << "|BAR = Barcelona |" << endl;
cout << "|ROM = ROME |" << endl;
cout << "|DUB = DUBAI |" << endl;
cout << "| |" << endl;
cout << "|___________________|" << endl;
cout << endl;
cout << endl;
cout << endl;
entry = "Please enter the ID code of the starting destination.\n";
while (needtoentercodes == false)
{
cout<< entry;
cout << "Use the key above to see which airports are available. \n";
string userdepartid;
cin>> userdepartid;
bool k = false;
//VALIDATING USER INPUT FOR DEPARTURE AIRPORT CODE - As mentioned above, this little section validates the starting departure id code.
while (k==false){
if ((userdepartid != "HEA") && (userdepartid != "EMA") && (userdepartid != "DUB") && (userdepartid != "BAR") && (userdepartid != "ROM"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userdepartid;
}
else
{
k=true;
}
}
cout << "\n";
cout << "Please enter the code of the arrival destination.\n";
string userarrivalid;
cin >> userarrivalid;
//VALIDATING USER INPUT FOR ARRIVAL AIRPORT CODE - This little section of code validates the arrival id airport code inputted in by the user.
bool a = false;
while (a==false){
if ((userarrivalid != "HEA") && (userarrivalid != "EMA") && (userarrivalid != "ROM") && (userarrivalid != "DUB") && (userarrivalid != "BAR"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userarrivalid;
}
else
{
a=true;
}
}
int j = 1;
bool resultsfound = false;
cout << "\n";
//RETURN THE RESULTS AND PUT THE RESULTS IN AN ARRAY - This little section places the searched results in a unique vector which then can be used later on in the program.
for (int i=0; i < flightDetails.size(); i++)
{
string tempflightdata = flightDetails[i];
string departid = tempflightdata.substr(0,3);
string arrivalid = tempflightdata.substr(4,3);
if ((departid == userdepartid) && (arrivalid == userarrivalid))
{
cout << j << ":" << flightDetails[i] << "\n";
flightSearch.push_back(flightDetails[i]);
j++;
needtoentercodes = false;
}
else
{
entry = "| Incorrect Entry. No direct connections! |\nPlease enter the ID code of the starting destination.\n";
}
}
}
}
It's the old, old problem
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
should be
while (getline (flightdata, flightnextline))
{
flightDetails.push_back(flightnextline);
}
flightdata.close();
Your while loop goes round one too many times because flightdata is still good() even after you've read the last line, and so you end up adding a blank line to your flightDetails vector. Later when you do tempflightdata.substr(4,3); on a blank line this causes the out_of_range error you see.
Caveat, I've only looked at the code, not debugged it.