map/set iterator is not dereferencable C++ map - c++

Please, have a look at my code.
int main () {
Program* allcommand = new Program;
allcommand->addCommand("add", new Add);
allcommand->addCommand("convert", new Convert);
allcommand->addCommand("exit", new Exit);
allcommand->addCommand("help", new Help);
allcommand->addCommand("show", new Show);
allcommand->addCommand("modify", new Modify);
std::string input;
Command* obj;
while (true) {
std::cout << "\nCommand >> ";
std::getline(std::cin, input);
std::map<std::string, Command*> :: iterator it;
std::vector<std::string> parsedinput = allcommand->parse(input);
it = allcommand->getCommands().find(parsedinput[0]);
obj = it->second;
obj->start(parsedinput);
delete obj;
}
return 0;
}
It registers commands to a map which holds its command name and pointer to its class.
This compiles without problems but when I enter a command, it crashes with "map/set iterator not dereferencable". I am new to maps (few minutes) so please help.
EDIT. Ok I found that the problem is not in main... Here is code of Program class (some of it)
void Program::addCommand(std::string command1, Command* obj) {
m_allCommands[command1] = obj;
}
std::map<std::string, Command*> Program::getCommands () {
return m_allCommands;
}
I think the problem is here, because after i register commands in main, I cannot cout the name of any command (same problem)

std::map<std::string, Command*> Program::getCommands () {
return m_allCommands;
}
returns a copy of the m_allcommands map. So when you do:
it = allcommand->getCommands().find(parsedinput[0]);
You get an iterator on the temporary object returned by allcommand->getCommands() that gets destroyed when the assignment is done. Therefore it points to nothing.
Change getCommands() to:
std::map<std::string, Command*>& Program::getCommands () {
return m_allCommands;
}
or even better:
const std::map<std::string, Command*>& Program::getCommands () const {
return m_allCommands;
}

After a call to find() you need to check if
if(it == allcommand->getCommands().end()) {
//Not Found
} else {
obj = it->second;
obj->start(parsedinput);
}

Related

Cannot erase a shared_ptr from set

I am trying to have an object with a set of pointers to another object. when I try to erase on of the set's values I get an error and crash, I really dont know what could be causing it. here is the library and after that the main function:
when I try to run it it does everything its supposed to do, and when it gets to the removeemployee it crashes and sends out the following: Process finished with exit code -1073740940 (0xC0000374)
I run it on clion if that matters, and in c++11.
#include <ostream>
#include <iostream>
#include "Manager.h"
Manager::Manager(int id, string firstName, string lastName, int birthYear)
: Citizen(id, firstName, lastName,birthYear), salary(0), employees(), work_flag(false) {}
int Manager::getSalary() const {
return salary;
}
void Manager::setSalary(int _salary) {
if((salary + _salary) < 0){
salary = 0;
}else {
salary += _salary;
}
}
void Manager::addEmployee(Employee* employee_add) {
shared_ptr<Employee> employee(employee_add);
if(employees.find(employee) != employees.end()){
throw mtm::EmployeeAlreadyExists();
}
employees.emplace(employee);
}
//this is the function
void Manager::removeEmployee(int id) {
for(auto it = employees.begin(); it != employees.end(); it++){
if(it->get()->getId() == id){
employees.erase(it);
return;
}
}
throw mtm::EmployeeDoesNotExists();
}
Manager *Manager::clone() {
return new Manager(*this);
}
ostream &Manager::printShort(ostream &os) const {
os<<this->getFirstName()<<" "<<this->getLastName()<<endl;
os<<"Salary :"<<this->getSalary()<<endl;
return os;
}
ostream &Manager::printLong(ostream &os) const {
os<<this->getFirstName()<<" "<<this->getLastName()<<endl;
os<<"id - "<<this->getId()<<" birth_year - "<<this->getBirthYear()<<endl;
os<<"Salary :"<<this->getSalary()<<endl;
os<<"Employees:"<<endl;
for(const auto & employee : employees){
employee->printShort(os);
}
return os;
}
bool Manager::findEmployee(int id) {
int i = 0;
for(const auto & employee : employees){
cout<<++i<<endl;
if(employee->getId() == id){
cout<<"return true"<<endl;
return true;
}
}
cout<<"return false"<<endl;
return false;
}
bool Manager::isWorkFlag() const {
return work_flag;
}
void Manager::setWorkFlag(bool workFlag) {
work_flag = workFlag;
}
and this is the main function:
int main() {
Employee e1(1, "John", "Williams", 2002);
Employee e2(2, "Alex", "Martinez", 2000);
Manager m1(1,"Robert", "stark", 1980);
m1.addEmployee(&e1);
m1.addEmployee(&e2);
Employee e3(7, "Reuven", "Guetta", 2001);
m1.addEmployee(&e3);
m1.printLong(cout);
cout<<"Delete"<<endl;
//here is the problem
m1.removeEmployee(e2.getId());
m1.printLong(cout);
return 0;
}
shared_ptr<Employee> employee(employee_add);
There is only one reason to have a shared_ptr, in the first place; there's only one reason for its existence; it has only one mission in its life, as explained in every C++ textbook: to be able to new an object, and have the shared_ptr automatically take care of deleteing it when all references to the object are gone, avoiding a memory leak.
In your program this object was not instantiated in dynamic scope with new:
Employee e2(2, "Alex", "Martinez", 2000);
Manager m1(1,"Robert", "stark", 1980);
m1.addEmployee(&e1);
// etc, etc, etc...
and that's the reason for the crash.
If you are not using new, simply get rid of all shared_ptrs in the shown code.

vector<string> doesnt work when using seperate classes

I have a txt file which has a rogue-like level
I load it like so:
void File::LoadLevel()
{
ifstream input_file;
input_file.open("Level_1.txt");
if (input_file.fail())
{
perror("Level_1.txt");
}
while (input_file >> _level)
{
_level_instance.push_back(_level);
}
}
variables:
string _level;
vector<string> _level_instance;
I print it out like this:
for (int i = 0; i < _level_instance.size(); i++)
{
cout << _level_instance[i] << endl;
}
which works fine.
however I have a vector in another class as well and i use a getter like this:
vector<string>GetlevelData(){ return _level_data; }
and I change the LoadLevel() from this:
_level_instance.push_back(_level);
to this:
Level Lvl;
Lvl.GetLevelData().pushback(_level);
I make an method in 'Level' class which prints it out to the screen same as before
it compiles but it doesnt print out anything why?
By the way in the int main() neccesary methods are executed which is OpenLevel() from File class and Print() from Level class
EDIT:
passing it &by reference didnt work
here are both methods in Level.h:
void SetLevelData(const std::string &string) {
_level_data.push_back(string);
}
//Getters
vector<string>& GetlevelData(){ return _level_data; }
in File.cpp:
void File::LoadLevel()
{
ifstream input_file;
Level lvl;
input_file.open("Level_1.txt");
if (input_file.fail())
{
perror("Level_1.txt");
}
while (input_file >> _level)
{
lvl.GetlevelData().push_back(_level);
}
}
it doesnt work it prints nothing, even though i added '&'
the result is same when i try it with 'push_back' method in Level.h
Here is int main() just in case:
int main()
{
File f;
Level lvl;
f.LoadLevel();
lvl.PrintLevel();
system("PAUSE");
return 0;
}
And PrintLevel() in Level.cpp:
void Level::PrintLevel()
{
for (int i = 0; i < _level_data.size(); i++)
{
cout << _level_data[i] << endl;
}
}
The GetlevelData function returns its vector by value which means a whole new copy of it is created. Anything you push into that vector will be lost when the copy goes out of scope (which happens when the expression Lvl.GetLevelData().pushback(_level) is done).
You should return it by reference instead:
vector<string>& GetlevelData(){ return _level_data; }
// ^
// |
// Return by reference
vector<string>GetlevelData() returns a copy of the vector and not a reference to it.
So your Lvl.GetLevelData().push_back(_level); returns a copy adds data to the vector and then deletes that copy again. So you add it to a vector that will be immediately be deleted again.
You would need to return it either by reference:
vector<string>& GetlevelData(){ return _level_data; }
Or write a method to push back the data:
void push_back( const std::string &string) {
_level_data.push_back(string);
}

How do I return a Null Pointer in a function C++

I am currently working on a bit of code that will search within a vector of type Person (which I have defined in the code and will show if needed). If it finds the person, it returns their name. This is currently working, but if it does not find the person, it is supposed to return a Null pointer. The problem is, I cannot figure out how to make it return a Null pointer! It just keeps either crashing the program every time.
Code:
Person* lookForName(vector<Person*> names, string input)
{
string searchName = input;
string foundName;
for (int i = 0; i < names.size(); i++) {
Person* p = names[i];
if (p->getName() == input) {
p->getName();
return p; //This works fine. No problems here
break;
} else {
//Not working Person* p = NULL; <---Here is where the error is happening
return p;
}
}
}
You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
[&input](Person* p){ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
If the name you are searching for is not at the first element, then you are not searching in the rest of the elements.
You need to do something like -
for (int i = 0; i<names.size(); i++){
Person* p = names[i];
if (p->getName() == input) {
return p;
// Placing break statement here has no meaning as it won't be executed.
}
}
// Flow reaches here if the name is not found in the vector. So, just return NULL
return NULL;
As Chris suggested, try using std::find_if algorithm.
Looks like you just have to return Null, nullptr, or 0.
codeproject
Just use following code:
return NULL;

C++ Passing map from object

I am building a simple program to 'learn as I go', this program takes a couple of text files and processors them, each line of the first text file is information about a person, and for each line an Object (of type Student (see below)) is created and added to a vector.
Within the Student objects is a map that stores that students marks.
I have a function within the student class that returns the map when called (or at least thats what im trying to do).
Currently this function is:
marksType Student::printMarks(){
return marks;
}
(Where marksType = std::map<string, float>)
and marks is the map of type marksType.
Then in my main function I have:
Student a = *qw;
studmarks = a.printMarks();
for (std::map<string, float>::iterator iter = studmarks.begin(); iter != studmarks.end(); iter++){
cout << "TEST" << endl;
}
Where qw is a pointer to a student object and studmarks is of type map<string, float>
The issue is that the cout doesn't get called so the iterator seems to skip (but the student object does have items in the marks map).
Heres the complete Student class
#include "Student.h"
using namespace std;
typedef std::map<string, float> marksType;
Student::Student(const string &name, int regNo) : Person(name){
marksType marks;
this->regNo = regNo;
}
int Student::getRegNo() const{
return regNo;
}
void Student::addMark(const string& module, float mark){
pair<marksType::iterator,bool> check;
check = marks.insert (pair<string,float>(module,mark));
if (check.second==false){
marks[module]=mark;
}
}
float Student::getMark(const string &module) const throw (NoMarkException){
if (marks.find(module) != marks.end()){
return marks.find(module)->second;
}
else throw NoMarkException();
}
float Student::getAverageMark() const throw (NoMarkException){
if (!marks.empty()){
float avgmark = 0;
for (marksType::const_iterator avgit=marks.begin(); avgit!=marks.end(); ++avgit){
avgmark = avgmark + avgit->second;
}
avgmark = avgmark/marks.size();
return avgmark;
}
else throw NoMarkException();
}
marksType Student::printMarks(){
return marks;
}
Oh and below is the part of the main function that adds marks to the students,
for (vector<Student>::iterator it = students.begin(); it != students.end(); ++it){
Student b = *it;
if (regno == b.getRegNo()){
found = true;
b.addMark(module, mark);
}
}
I know this works because when I use the getMark function it does work.
You are "adding marks" to copies of the students stored in vector students. Each of these copies only lives during one iteration of the loop and the result is that you are not modifying the vector's elements at all:
for (vector<Student>::iterator it = students.begin(); it != students.end(); ++it){
Student b = *it; // b IS A COPY
if (regno == b.getRegNo()){
found = true;
b.addMark(module, mark); // modify local copy of Student
}
}
To add them to the elements of the vector, use
for (vector<Student>::iterator it = students.begin(); it != students.end(); ++it){
if (regno == it->getRegNo()){
found = true;
it->addMark(module, mark);
}
}

STL list<mystruct> return problem

I am trying to use STL list in a project but i have the following problem.
I want my list to store a struct. For example this one
struct mystruct
{
int x;
int y;
};
Then i am using an iterator to access every struct in the list like this.
list<mystruct> L;
list<mystruct>::iterator lit;
for(lit=L.begin();lit!=L.end();lit++)
{
if(lit->x==1) cout << "<NUM," << lit->x << "> ";
if(lit->y==2) cout << "<ID," << lit->y << "> ";
}
This works but i want to get one struct at a time so i made this func
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
but i get an error after running it and i cannot understand why this happens.
Any ideas what is going wrong?
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
You increment unless you already are at the end, but the dereferencing happens every time, regardless of if you are at the end or not. To help around that problem, consider returning a pointer, and then a 0 pointer if you are at the end.
mystruct* Myclass::next(void)
{
if(lit!=L.end() && ++lit != L.end())
{
// dereference to get the struct, and then return the address of the struct
return &*lit;
}
return 0;
// or nullptr in C++0x
}
And then check agains 0 (or nullptr) in the code where you use Myclass::next.
If you're writing next() that returns an object (rather than pointer), then I think you also need to write has_next() function which you should call to inspect if there is item in the list or not, before calling next(). Something like this:
bool has_next()
{
list<mystruct>::iterator temp = lit;
return ++temp != L.end();
}
mystruct Myclass::next(void)
{
if( !has_next())
{
throw "end of the list is reached";
}
++lit;
return *lit;
}
//usage
while(myClassInstance.has_next())
{
mystruct s = myClassInstance.next();
//work with s
}
Or if you decide to return pointer to mystruct from next(), then has_next() is not so needed. You can write this:
mystruct * Myclass::next(void)
{
++lit;
if( lit == L.end() )
return NULL;
return &(*lit);
}
The problem is here :
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
First how is lit defined?
Second, if lit is equal to L.end() you should return some default value, not dereference it, because if you do, you are causing an undefined behaviour. If you are lucky, your program will crash.