访问成员时生成超出范围错误的结构向量 C++
Vector of structs generating out-of-range error when member is accessed C++
我正在编写图书馆应用程序。应用程序的一部分允许用户登录。我正在使用结构向量来存储 usernames/passwords。当我尝试访问结构的成员变量时,出现超出范围错误。向量已满(我检查了 vector.size 和 vector.empty 方法),我相信我正确地为成员变量赋值(尽管显然我不是)。
这里是main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "userService.h"
using namespace std;
void countRecords(string& pathName, ifstream& inFile);
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser);
void login(string username, string password, userService newUser, bool& loggedIn);
int numRecords;
int main()
{
string username, password;
string pathName = "/home/seth/Desktop/credentials";
ifstream inFile;
userService newUser;
char menuSelection;
bool loggedIn = false;
countRecords(pathName, inFile);
cout << "Welcome to Library Information System." << endl << endl;
do{
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
cout << endl;
loadCredentials(pathName, inFile, username, password, newUser);
login(username, password, newUser, loggedIn);
if (loggedIn == true)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
break;
}
}
} while (loggedIn == false);
return 0;
}
void countRecords(string& pathName, ifstream& inFile)
{
string temp; //string to count records using getline
inFile.open(pathName);
while (inFile)
{
getline(inFile, temp, '\n');
if (inFile.eof())
{
break;
}
++numRecords;
}
cout << "numRecords = " << numRecords << endl;
inFile.close();
inFile.clear(std::ios_base::goodbit);
}
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser)
{
string tempUsername, tempPassword;
inFile.open(pathName);
if (!inFile)
{
cout << "Error opening file" << endl;
}
for (int i = 0; i < numRecords; i++)
{
getline(inFile, tempUsername, ',');
getline(inFile, tempPassword, '\n');
newUser.loadCredentials(tempUsername, tempPassword);
}
}
void login(string username, string password, userService newUser, bool& loggedIn)
{
newUser.resetVectorCounter();
for (size_t i = 0; i < numRecords; i++)
{
cout << "i = " << i << endl;
cout << newUser.getUsername() << endl;
cout << newUser.getPassword() << endl;
newUser.incrementVector();
}
}
userService.h:
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username = "";
string password = "";
};
class userService
{
private:
vector<credentials> credentialsList;
int vectorCounter = 0;
string username_, password_;
public:
void loadCredentials(string username_, string password_);
bool check();
int sizeOfVec();
string getUsername();
string getPassword();
void incrementVector();
void resetVectorCounter();
};
用户服务的实现:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include "userService.h"
using namespace std;
credentials users;
void userService::loadCredentials(string username_, string password_)
{
users.username = username_;
users.password = password_;
credentialsList.push_back(users);
}
bool userService::check()
{
return credentialsList.empty();
}
int userService::sizeOfVec()
{
return credentialsList.size();
}
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
string userService::getPassword()
{
return credentialsList.at(vectorCounter).password;
}
void userService::incrementVector()
{
vectorCounter++;
}
void userService::resetVectorCounter()
{
vectorCounter = 0;
}
抛出的确切错误是:
'std::out_of_range'
what(): vector::_M_range_check: __n (即0) >= this->size (即0)
这在调用 getUserName 后立即发生。我相信这意味着成员变量是空的,但如果是这样,我不知道如何正确地给它们赋值。任何帮助将不胜感激。
我试过使用调试器,这里是调试器显示此问题的地方:
protected:
/// Safety check used only from at().
void
_M_range_check(size_type __n) const
{
if (__n >= this->size())
__throw_out_of_range_fmt(__N("vector::_M_range_check: __n "
"(which is %zu) >= this->size() "
"(which is %zu)"),
__n, this->size());
}
您的代码确实使用越界索引访问 std::vector
。
这是我机器上 gdb 的堆栈跟踪:
#0 0x00007ffff74aa428 in __GI_raise (sig=sig@entry=6)
at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff74ac02a in __GI_abort () at abort.c:89
#2 0x00007ffff7ae484d in __gnu_cxx::__verbose_terminate_handler() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff7ae26b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff7ae2701 in std::terminate() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff7ae2919 in __cxa_throw ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007ffff7b0b3f7 in std::__throw_out_of_range_fmt(char const*, ...) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x00000000004029b6 in std::vector<credentials, std::allocator<credentials> >::_M_range_check (this=0x7fffffffe320, __n=0)
at /usr/include/c++/5/bits/stl_vector.h:803
#8 0x00000000004024cf in std::vector<credentials, std::allocator<credentials> >::at (this=0x7fffffffe320, __n=0) at /usr/include/c++/5/bits/stl_vector.h:824
#9 0x000000000040179d in userService::getUsername[abi:cxx11]() (
this=0x7fffffffe320) at socc.cc:61
#10 0x0000000000402059 in login (username="a", password="aa", newUser=...,
loggedIn=@0x7fffffffe19f: false) at socc.cc:185
#11 0x0000000000401aa4 in main () at socc.cc:120
我的 "credentials" 文件有以下几行:
a,aa
b,bb
c,cc
因此,当我使用 "a" 作为用户名和 "aa" 作为密码时,应该可以登录成功。
但是,您有:
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
调用该函数时,credentialsList
为空,vectorCounter
为 0
。那不行。
这就解释了为什么会出现错误。然而,修复并不简单。
我认为您不清楚 "credentials" 文件中的数据需要如何存储以及如何使用它们来验证用户身份。
这里有几点值得思考。
userService
可以提供对用户进行身份验证的能力。但是,它不是用户。因此,为什么将 username_
和 password_
作为 class.
的成员变量完全没有意义
"credentials" 文件中的凭据列表是程序的全局数据。将它们存储在 userService
的成员变量中是没有意义的,除非您的程序可以保证只有 userService
.
的实例
将vectorCounter
作为userService
的成员变量也毫无意义。当您需要遍历向量的元素时,有更好的选择。不仅如此,迭代的逻辑应该是函数局部的,其任何局部变量都应该是函数局部变量。
userService
的许多成员函数不适合class的职责。唯一对我有意义的成员函数是:
void loadCredentials(string filename);
bool authenticateUser(credentials const& c);
这是一个适合我的更新程序(除了你没有任何代码供用户选择 'b')。
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username;
string password;
};
class userService
{
private:
vector<credentials> credentialsList;
public:
void loadCredentials(string filename);
bool authenticateUser(credentials const& c);
};
void userService::loadCredentials(string filename)
{
string tempUsername, tempPassword;
std::ifstream inFile(filename);
if (!inFile)
{
cout << "Error opening file" << endl;
}
while (inFile )
{
if ( !getline(inFile, tempUsername, ',') )
{
return;
}
if ( !getline(inFile, tempPassword, '\n') )
{
return;
}
credentialsList.push_back(credentials{tempUsername, tempPassword});
}
}
bool userService::authenticateUser(credentials const& c)
{
for ( auto const& item : credentialsList )
{
if ( item.username == c.username &&
item.password == c.password )
{
return true;
}
}
return false;
}
int main()
{
string username, password;
// string pathName = "/home/seth/Desktop/credentials";
string pathName = "credentials";
// The only instance of userService used in the program.
userService service;
char menuSelection;
bool loggedIn = false;
// Load the credentials file once and then use for all subsequent checks.
service.loadCredentials(pathName);
cout << "Welcome to Library Information System." << endl << endl;
do {
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
credentials c = {username, password};
// The only instance of userService has all the credentials.
// It can authenticate the user credentials.
loggedIn = service.authenticateUser(c);
if (loggedIn)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
}
break;
// Missing code for case 'b'
// case 'b':
}
} while (loggedIn == false);
return 0;
}
我正在编写图书馆应用程序。应用程序的一部分允许用户登录。我正在使用结构向量来存储 usernames/passwords。当我尝试访问结构的成员变量时,出现超出范围错误。向量已满(我检查了 vector.size 和 vector.empty 方法),我相信我正确地为成员变量赋值(尽管显然我不是)。
这里是main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "userService.h"
using namespace std;
void countRecords(string& pathName, ifstream& inFile);
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser);
void login(string username, string password, userService newUser, bool& loggedIn);
int numRecords;
int main()
{
string username, password;
string pathName = "/home/seth/Desktop/credentials";
ifstream inFile;
userService newUser;
char menuSelection;
bool loggedIn = false;
countRecords(pathName, inFile);
cout << "Welcome to Library Information System." << endl << endl;
do{
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
cout << endl;
loadCredentials(pathName, inFile, username, password, newUser);
login(username, password, newUser, loggedIn);
if (loggedIn == true)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
break;
}
}
} while (loggedIn == false);
return 0;
}
void countRecords(string& pathName, ifstream& inFile)
{
string temp; //string to count records using getline
inFile.open(pathName);
while (inFile)
{
getline(inFile, temp, '\n');
if (inFile.eof())
{
break;
}
++numRecords;
}
cout << "numRecords = " << numRecords << endl;
inFile.close();
inFile.clear(std::ios_base::goodbit);
}
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser)
{
string tempUsername, tempPassword;
inFile.open(pathName);
if (!inFile)
{
cout << "Error opening file" << endl;
}
for (int i = 0; i < numRecords; i++)
{
getline(inFile, tempUsername, ',');
getline(inFile, tempPassword, '\n');
newUser.loadCredentials(tempUsername, tempPassword);
}
}
void login(string username, string password, userService newUser, bool& loggedIn)
{
newUser.resetVectorCounter();
for (size_t i = 0; i < numRecords; i++)
{
cout << "i = " << i << endl;
cout << newUser.getUsername() << endl;
cout << newUser.getPassword() << endl;
newUser.incrementVector();
}
}
userService.h:
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username = "";
string password = "";
};
class userService
{
private:
vector<credentials> credentialsList;
int vectorCounter = 0;
string username_, password_;
public:
void loadCredentials(string username_, string password_);
bool check();
int sizeOfVec();
string getUsername();
string getPassword();
void incrementVector();
void resetVectorCounter();
};
用户服务的实现:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include "userService.h"
using namespace std;
credentials users;
void userService::loadCredentials(string username_, string password_)
{
users.username = username_;
users.password = password_;
credentialsList.push_back(users);
}
bool userService::check()
{
return credentialsList.empty();
}
int userService::sizeOfVec()
{
return credentialsList.size();
}
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
string userService::getPassword()
{
return credentialsList.at(vectorCounter).password;
}
void userService::incrementVector()
{
vectorCounter++;
}
void userService::resetVectorCounter()
{
vectorCounter = 0;
}
抛出的确切错误是:
'std::out_of_range' what(): vector::_M_range_check: __n (即0) >= this->size (即0)
这在调用 getUserName 后立即发生。我相信这意味着成员变量是空的,但如果是这样,我不知道如何正确地给它们赋值。任何帮助将不胜感激。
我试过使用调试器,这里是调试器显示此问题的地方:
protected:
/// Safety check used only from at().
void
_M_range_check(size_type __n) const
{
if (__n >= this->size())
__throw_out_of_range_fmt(__N("vector::_M_range_check: __n "
"(which is %zu) >= this->size() "
"(which is %zu)"),
__n, this->size());
}
您的代码确实使用越界索引访问 std::vector
。
这是我机器上 gdb 的堆栈跟踪:
#0 0x00007ffff74aa428 in __GI_raise (sig=sig@entry=6)
at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff74ac02a in __GI_abort () at abort.c:89
#2 0x00007ffff7ae484d in __gnu_cxx::__verbose_terminate_handler() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff7ae26b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff7ae2701 in std::terminate() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff7ae2919 in __cxa_throw ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007ffff7b0b3f7 in std::__throw_out_of_range_fmt(char const*, ...) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x00000000004029b6 in std::vector<credentials, std::allocator<credentials> >::_M_range_check (this=0x7fffffffe320, __n=0)
at /usr/include/c++/5/bits/stl_vector.h:803
#8 0x00000000004024cf in std::vector<credentials, std::allocator<credentials> >::at (this=0x7fffffffe320, __n=0) at /usr/include/c++/5/bits/stl_vector.h:824
#9 0x000000000040179d in userService::getUsername[abi:cxx11]() (
this=0x7fffffffe320) at socc.cc:61
#10 0x0000000000402059 in login (username="a", password="aa", newUser=...,
loggedIn=@0x7fffffffe19f: false) at socc.cc:185
#11 0x0000000000401aa4 in main () at socc.cc:120
我的 "credentials" 文件有以下几行:
a,aa
b,bb
c,cc
因此,当我使用 "a" 作为用户名和 "aa" 作为密码时,应该可以登录成功。
但是,您有:
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
调用该函数时,credentialsList
为空,vectorCounter
为 0
。那不行。
这就解释了为什么会出现错误。然而,修复并不简单。
我认为您不清楚 "credentials" 文件中的数据需要如何存储以及如何使用它们来验证用户身份。
这里有几点值得思考。
userService
可以提供对用户进行身份验证的能力。但是,它不是用户。因此,为什么将username_
和password_
作为 class. 的成员变量完全没有意义
"credentials" 文件中的凭据列表是程序的全局数据。将它们存储在
userService
的成员变量中是没有意义的,除非您的程序可以保证只有userService
. 的实例
将
vectorCounter
作为userService
的成员变量也毫无意义。当您需要遍历向量的元素时,有更好的选择。不仅如此,迭代的逻辑应该是函数局部的,其任何局部变量都应该是函数局部变量。userService
的许多成员函数不适合class的职责。唯一对我有意义的成员函数是:void loadCredentials(string filename); bool authenticateUser(credentials const& c);
这是一个适合我的更新程序(除了你没有任何代码供用户选择 'b')。
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username;
string password;
};
class userService
{
private:
vector<credentials> credentialsList;
public:
void loadCredentials(string filename);
bool authenticateUser(credentials const& c);
};
void userService::loadCredentials(string filename)
{
string tempUsername, tempPassword;
std::ifstream inFile(filename);
if (!inFile)
{
cout << "Error opening file" << endl;
}
while (inFile )
{
if ( !getline(inFile, tempUsername, ',') )
{
return;
}
if ( !getline(inFile, tempPassword, '\n') )
{
return;
}
credentialsList.push_back(credentials{tempUsername, tempPassword});
}
}
bool userService::authenticateUser(credentials const& c)
{
for ( auto const& item : credentialsList )
{
if ( item.username == c.username &&
item.password == c.password )
{
return true;
}
}
return false;
}
int main()
{
string username, password;
// string pathName = "/home/seth/Desktop/credentials";
string pathName = "credentials";
// The only instance of userService used in the program.
userService service;
char menuSelection;
bool loggedIn = false;
// Load the credentials file once and then use for all subsequent checks.
service.loadCredentials(pathName);
cout << "Welcome to Library Information System." << endl << endl;
do {
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
credentials c = {username, password};
// The only instance of userService has all the credentials.
// It can authenticate the user credentials.
loggedIn = service.authenticateUser(c);
if (loggedIn)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
}
break;
// Missing code for case 'b'
// case 'b':
}
} while (loggedIn == false);
return 0;
}