C++ Cannot use push_back on list containing custom structs - c++

We are making a list that hold info on boardgames (name, year, score). We scan the info out of a .csv file, make a struct based on that info and then add the struct to a list. We keep doing this untill the document is done reading. Problem is that the push_back method of the list doesn't work. Here's the header of the list class:
NOTE BoardGame is the custom struct. BoardGame(wstring name, int year, float score).
#pragma once
#include "GameEngine.h"
#include "BoardGame.h"
#include <list>
class BoardGameList
{
public:
BoardGameList() {}
virtual ~BoardGameList() {}
// Methods
void Load(const tstring& fileName);
// Members
private:
std::list<BoardGame> m_Games;
};
The cpp file. Maybe I made the list the wrong way?
#include "BoardGameList.h"
#include <fstream>
void BoardGameList::Load(const tstring& fileName)
{
tifstream file(fileName);
tstring line;
if(!file)
{
GAME_ENGINE->MessageBox(_T("Error: The file could not be found!"));
}
else
{
tstring name;
tstring year;
tstring score;
while(!(file.eof()))
{
getline(file,line);
year = line.substr(0,4);
score = line.substr(5,5);
name = line.substr(11,line.find(_T("\n")));
float numberScore = std::stof(score);
int numberYear = std::stoi(year);
m_Games.push_back(BoardGame(name,numberYear,numberScore));
}
}
}
Running the program triggers an error (unhandled exception) that leads me to the following code in the "list" class itself I think.
_Unchecked_iterator _Unchecked_end()
{ // return unchecked iterator for end of mutable sequence
return (_Unchecked_iterator(this->_Myhead, this));
}
Any ideas why I can't add stuff to my list? I tried adding something in the constructor to check if it maybe needed an element before I could add more but even then, using a breakpoint showed me that the memory could not be read.
Many thanks in advance.
EDIT: Header of BoardGame
#pragma once
#include "GameEngine.h"
struct BoardGame
{
BoardGame(tstring name, int year, float score);
//Methods
tstring operator<<(BoardGame rhs);
//Members
tstring m_Name;
int m_Year;
float m_Score;
};

What exception is being thrown? This is vital to debugging your problem.
Without that information my best guess is this line:
name = line.substr(11,line.find(_T("\n")));
Will throw an exception on any line without a trailing newline, or any line less than 11 characters long.

Related

No declaration matches in Codelite IDE

I have been looking in different threads with this error which is quite common but it feels like the IDE I am using messed with my workspace and I can't quite find the problem. I am setting up an extremely basic class called "Movie" that is specified below:
Movie.hpp :
#ifndef MOVIE_HPP
#define MOVIE_HPP
#include <iostream>
#include <string>
using std::string, std::cout,std::size_t;
class Movie
{
private:
std::string name;
std::string rating;
int watched_ctr;
public:
Movie(const string& name, const string& rating, int watched_ctr);
~Movie();
//getters
string get_name() const;
string get_rating() const;
int get_watched() const;
//setters
void set_name(string name);
void set_rating(string rating);
void set_watched(int watched_ctr);
};
#endif // MOVIE_HPP
Movie.cpp:
#include <iostream>
#include <string>
#include "Movie.hpp"
using std::string, std::cout,std::size_t,std::endl;
Movie::Movie(const string& name, const string& rating, int watched_ctr)
: name(name) , rating(rating) , watched_ctr(watched_ctr) {
}
Movie::~Movie()
{
cout << "Destructor for Movies class called /n";
}
//Getters
string Movie::get_name(){return name;}
string Movie::get_rating(){return rating;}
string Movie::get_watched(){return watched_ctr;}
//Setters
void Movie::set_name(std::string n){this -> name = n;}
void Movie::set_rating(std::string rating){this -> rating = rating;}
void Movie::set_watched(int ctr){this -> watched_ctr = ctr;}
The main.cpp I am trying only consists in creating one Movie object:
#include <iostream>
#include <string>
#include "Movie.hpp"
using std::string, std::cout,std::size_t,std::endl;
int main()
{
Movie StarTrek("Star Trek", "G", 20);
}
As you can see, I set all the attribute to private in order to exercise with the set/get methods but I keep stumbling upon the same error on each of them stating >"C:/Users/.../ProjectsAndTests/MoviesClass/Movie.cpp:18:8: error: no declaration matches 'std::__cxx11::string Movie::get_name()"
if you could give me a hint on what might cause this error I would greatly appreciate thank you!
I tried opening another workspace with classes implemented inside of them and the syntax I am using is very close from this test workspace I opened which compiled fine (no error regarding declaration match).
There are 2 problems with your code.
First while defining the member functions outside class you're not using the const. So to solve this problem we must use const when defining the member function outside the class.
Second, the member function Movie::get_watched() is declared with the return type of string but while defining that member function you're using the return type int. To solve this, change the return type while defining the member function to match the return type in the declaration.
//----------------------vvvvv--------->added const
string Movie::get_name()const
{
return name;
}
string Movie::get_rating()const
{
return rating;
}
vvv------------------------------>changed return type to int
int Movie::get_watched()const
{
return watched_ctr;
}
Working demo

Adding data inside unordered_map inside a class

I have a class Citydata, defined in .hh file
struct City_details {
string name;
int taxrate;
};
class Citydata {
public:
bool add_data(string id, string name, int taxrate)
//other member functions...
private:
unordered_map<id, City_details> info_map;
I have trouble implementing the add_data function in .cc file. Here is my try.
bool Citydata::add_data(string id, string name, int taxes) {
if ( info_map.find(id) == info_map.end()) {
City_details dataload;
dataload.name = name;
dataload.taxrate = taxes;
info_map[id] = dataload;
return true;
}
else return false;
}
When I test this, I cannot see any data added the way I wanted. Instead I see one completely empty entry (default empty values), and one entry with right id (the key) but no data added to the parameters. Each time I call add_data, it creates similar pair of one completely empty key-data member, then one with right id and otherwise empty data.
The original program is much longer than this, so problem might persist there too, but I wonder if my approach is flawed by design.
I have made some modifications that makes your program work.
First you should replace unordered_map<id, City_details> info_map; with unordered_map<std::string, City_details> info_map;
Second you had a missing semicolon ; for you add_data member function declaration inside the class which you might have missed while copy pasting the code here on Stackoverflow.
Third i have avoided the use of using namespace std;.
main.cpp
#include <iostream>
#include "file.h"
int main()
{
Citydata c1;
c1.add_data("id1","Georgia", 34);
c1.add_data("id2", "California", 32);
c1.add_data("id3","Texas", 23);
//lets print out the element of info_map
for(auto &it:c1.info_map)
std::cout << it.first <<" "<<it.second.name<<" "<<it.second.taxrate<<std::endl;
return 0;
}
file.h
#pragma once
#include <unordered_map>
#include <string>
struct City_details {
std::string name;
int taxrate;
};
class Citydata {
public:
bool add_data(std::string id, std::string name, int taxrate);
//other member functions...
//private:
std::unordered_map<std::string, City_details> info_map;//the first tempate argument should be int and not id
};
file.cpp
#include "file.h"
bool Citydata::add_data(std::string id, std::string name, int taxes) {
if ( info_map.find(id) == info_map.end()) {
City_details dataload;
dataload.name = name;
dataload.taxrate = taxes;
info_map[id] = dataload;
return true;
}
else return false;
}

Why is my class constructor being called twice?

I've got a base class Container with a derived class Player_Inventory. There can only be one Player_Inventory so my code throws an exception if for some reason a second one is created.
The problem I'm having is that my code is failing my test as it throws the exception even on what is supposed to be the very first construction of the Player_Inventory class. I've debugged the code and two things are happening which I don't quite understand - the number attribute is not tracked by the debugger (at least not in the GUI on VSC), and it seems that right after hitting the first REQUIRE statement, the constructor is called again, thus triggering the exception.
Can anyone help?
After rewriting my constructor method, I'm still getting a similar error.
My revised code is as follows:
containers.h
#include<iostream>
#include<string>
#include<vector>
class Item { // Placeholder class for items
public:
std::string name;
Item(std::string n) : name{n} {};
};
class Container {
protected:
std::string name;
std::string description;
std::vector<Item> contents;
public:
Container(std::string, std::string);
std::string get_name() {return name;}
std::string get_description() {return description;}
std::vector<Item> get_contents() {return contents;}
};
containers.cpp (there are more methods defined in this file which aren't used here)
#include<iostream>
#include<string>
#include "containers.h"
Container::Container(std::string n, std::string desc) : name{n}, description{desc} {};
player_inventory.h
#include "containers.h"
class Player_Inventory : public Container {
public:
static int number;
Player_Inventory(std::string, std::string);
};
player_inventory.cpp
#include<iostream>
#include<stdexcept>
#include "player_inventory.h"
Player_Inventory::Player_Inventory(std::string n, std::string desc): Container(n, desc) {
number += 1;
if (number > 1){
throw std::invalid_argument("You can only have one inventory!");
}
};
int Player_Inventory::number = 0;
test_file.cpp
#include "../lib/Catch2/catch.hpp"
#include "player_inventory.h"
#include<iostream>
#include<string>
#include<vector>
SCENARIO("A player can have an inventory.") {
WHEN("A player inventory is created.") {
Player_Inventory myInventory("My Inventory", "Inventory for the player");
THEN("The created inventory has the correct attribute values.") {
REQUIRE(myInventory.get_name() == "My Inventory");
REQUIRE(myInventory.get_description() == "Inventory for the player");
REQUIRE(myInventory.get_contents().empty());
} // The code works fine when only up to here is included
AND_THEN("Only one player inventory can exist.") { // as soon as this line is included it tries to create another player_inventory object, causing the fail
REQUIRE_THROWS((Player_Inventory myOtherInventory("Second Inventory", "Testing for another one"))); // These two lines were not included but I've included them here as this is the test I wanted to run
REQUIRE(myInventory.get_number() == 1);
}
}
}
Not sure if related, but that's how you should call the Base constructor:
Player_Inventory(std::string n, std::string desc) : Container(n, desc) {
}

C++ Using different subclasses based on part of input

I have some issues solving a task from class. My algorithm for solving the issues is working fine, but my problem is to read data from 3 different text files into 2 different classes.
Now the 1st text file "hours.txt" gives a string id and hour int, like so:
adam1;170
eve2;170
so, separated by a ";".
The next file contains the same id as before and name, taxid, type, and according to type: wage if PH, or salary and ovtwage if IS.
adam1;Adam Driver;12345678;PH;5;
eve2;Eve Assistant;23456789;IS;650;10
The 3rd file contains only the int 160, which is defined as generalWorkingHours. Now to where my problems are arising. I have experience in reading data from 1 file into 1 class but in this case I have to read data to 2 classes, ph and is depending on the type of the id's(adam1 and eve2). I have been provided two classes like this :
#ifndef IS_H
#define IS_H
#include "Employee.h"
#include <iostream>
using namespace std;
class is: public Employee
{
public:
is();
virtual ~is();
void setSalary(int salary);
int getSalary();
void setOvtWage(int ovtWage);
int getOvtWage();
protected:
private:
int salary;
int ovtWage;
};
#endif // IS_H
and
#ifndef PH_H
#define PH_H
#include "Employee.h"
#include <iostream>
using namespace std;
class ph: public Employee
{
public:
ph();
virtual ~ph();
void setWage(int wage);
int getWage();
protected:
private:
int wage;
};
#endif // PH_H
Both of these classes contain the public "Employee"
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <iostream>
using namespace std;
class Employee
{
public:
Employee();
virtual ~Employee();
void setId(string id);
string getId();
void setName(string name);
string getName();
void setTaxId(string taxid);
string getTaxId();
void setType(string type);
string getType();
void setHours(int hours);
int getHours();
protected:
private:
string id;
string name;
string taxid;
string type;
int hours;
};
#endif // EMPLOYEE_H
Now, usually I would create a function to read a file, and one to parse each line like so:
void Resolver::parseTextLine(string tmp, int & carCnt, carList X[]){
std::size_t found;
found=tmp.find(";");
if (found!=string::npos) {
X[carCnt].point=tmp.substr(0,found);
tmp=tmp.substr(found+1);
}
found=tmp.find(";");
if (found!=string::npos) {
X[carCnt].license=tmp.substr(0,found);
tmp=tmp.substr(found+1);
}
found=tmp.find(";");
if (found!=string::npos) {
X[carCnt].time=atoi(tmp.substr(0,found).c_str());
tmp=tmp.substr(found+1);
}
carCnt++;
}
void Resolver::readDataFromFiles(string carFile, int & carCnt, carList X[]){
carCnt=0;
ifstream finS(carFile.c_str(),ios::in);
bool first=true;
while (!finS.eof()) {
string tmp="";
getline(finS,tmp);
if (tmp!="") {
if (first) {
first=!first;
} else {
parseTextLine(tmp,carCnt,X);
}
}
}
finS.close();
}
NOTE: this is just an idea of how I am trying to solve it, but I have no experience with using multiple files and classes. All the functions are premade and I just need to patch it together somehow.
Assuming all the ids are unique, create a map<string, Employee*> Emp; This will store information of all the employee indexed by id as key ("adam1", "eve2") and object as value.
["adam1"] => [object of ph]
["eve2"] => [object of is]
Now, read file_2 which contains information about PH and IS. Now for each line read you will have all the components separated by ";" appearing in the line. After separating components from the line, you should be able to decide (using type) which derived class should be instantiated.
if(type == PH)
{
//suppose id = "adam"
ph *pEmployeePH = new ph();
//also set wage
//insert [id] in map Emp if not already present
}
if(type == IS)
{
//suppose id is now "eve2"
is *pEmployeeIS = new is();
//also set salary and ovtwage
//insert [id] in map Emp if not already present
}
Once you have your map ready, now read file_1. Now for each line read you will have 2 components separated by ";" appearing in the line. After separating components from the line, you should be able to decide (using id) which element of map Emp you should access/modify in order to set the hours.
Suppose id is "adam1" and hours=170, so now check whether map contains ["adam1"] and if does contain then set the hours as follows: Emp[id].setHours(hours);

How to insert class into stl map on class initialization

SOLVED: http://pastebin.com/seEaALZh
I was trying to create simple items system, where i can get item information by its id. I cant use array, because items ids are lets say random. I want to use declared items as variables and i want to quickly find any item info by its id. The only way i found is stl map.
So I have this simple code:
main.h
#include <iostream>
#include <map>
enum
{
weapon,
ammo
};
class c_items
{
bool operator()(const c_items& l, const c_items& r) const
{
return (l.id < r.id);
}
public:
c_items(void){};
c_items(int id, char name[], int type);
char *name;
int type;
int id;
};
extern std::map<int,c_items> Stuff;
c_items::c_items(int id, char name[], int type) : id(id), type(type), name(name)
{
Stuff[id] = c_items(id, name, type);
}
const c_items
brass_knuckles (546, "Brass knuckles", weapon),
golf_club (2165, "Gold club", weapon);
main.cpp
#include "main.h"
std::map<int,c_items> Stuff;
using namespace std;
int main()
{
// cout << Stuff[2165].name.data();
return 1;
}
And for some reason program crashes. How to correctly insert class data into map on class initialization?
The problem is order of initialization. The static constructors for brass_knuckles and golf_club run first, before the static constructor for Stuff, so they attempt to insert into a map that is not yet constructed.
In addition, you NEVER want variable DEFINITIONS in a header file, since if you include the header file in multiple source files, you end up with multiple definitions, which will at best cause a link failure. So you should move the DEFINITIONS out of the .h file and into the .cpp file. Putting them AFTER the definition of Stuff will fix the order of initialization problem.
You can have a DECLARATION of the variables in the header file if you want to use them in other compilation units:
extern const c_items brass_knuckles, golf_club;
you cannot put c_item in Stuff like that
instead
std::map<int,c_items> Stuff = { {item1.id, item1}, {item2.id, item2}};
but you also need to all the recommendation made by #Chris Dodd
so
c_items::c_items(int id, char name[], int type) : id(id), type(type), name(name)
{}
extern const c_items brass_knuckles, golf_club;
and in the main.cpp
const c_items brass_knuckles = {546, "Brass knuckles", weapon);
const c_items golf_club = (2165, "Gold club", weapon);
std::map<int,c_items> Stuff = { {brass_knuckles.id, brass_knuckles}, etc....};