C++ - List is not keeping its elements [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have 2 classes; TestUnit and TestShot.
TestUnit needs to hold a list of TestShots, however when I reference the list later on all the elements I've given it have disappeared!
TestUnit.h
#include <string>
#include <list>
#include "TestShot.h"
using namespace std;
class TestUnit
{
public:
TestUnit(string);
string getName(void);
void addShot(TestShot);
list<TestShot> getShots(void);
bool operator == (const TestUnit& tu) const { return name == tu.name; }
bool operator != (const TestUnit& tu) const { return !operator==(tu); }
private:
string name;
list<TestShot> shots;
};
TestUnit.cpp
#include "TestUnit.h"
TestUnit::TestUnit(string name)
{
this->name = name;
}
string TestUnit::getName(void)
{
return name;
}
void TestUnit::addShot(TestShot shot)
{
shots.push_front(shot);
}
list<TestShot> TestUnit::getShots(void)
{
return shots;
}
TestShot.h
#include <string>
using namespace std;
class TestShot
{
public:
TestShot(string);
string getName(void);
private:
string name;
};
TestShot.cpp
#include "TestShot.h"
TestShot::TestShot(string name)
{
this->name = name;
}
string TestShot::getName(void)
{
return name;
}
MAIN
#include <string>
#include "exports.h"
#include "TestUnit.h"
using namespace std;
// Global Variables
list<TestUnit> testUnits;
int main()
{
int nShots1 = 0;
int nShots2 = 0;
// Create Unit
TestUnit *testUnit = new TestUnit("Name");
testUnits.push_front(*testUnit);
// Create Shot and add to Unit with same 'name'
TestShot *testShot = new TestShot("Name");
for (TestUnit unit : testUnits)
{
if (unit.getName() == (*testShot).getName())
{
unit.addShot(*testShot);
nShots1 = unit.getShots().size();
}
}
// Display number of Shots for each Unit
for (TestUnit unit : testUnits)
{
nShots2 = unit.getShots().size();
std::cout << nShots1 << ", " << nShots2 << std::endl;
}
system("PAUSE");
};
Output:
1, 0
So the list realises that it's been populated straight after adding to it, but it's then empty when I need to use it.
I'm guessing this is a scope problem, but I can't seem to figure it out.
All help is much appreciated!

In each of your for loops, you're accessing the list elements by value, so you're effectively making a copy of what's in the list, modifying that, and then destroying it. Change your loops to look like this:
for (TestUnit &unit : testUnits)
{
if (unit.getName() == (*testShot).getName())
{
unit.addShot(*testShot);
nShots1 = unit.getShots().size();
}
}
Since you're using C++11 or later, you could also use auto instead of explicit typing (e.g., auto &unit: testUnits).

Related

Member function doesn't work when using pointer to class

Scenario: I have two classes, each contains a pointer to the other (when using them, being able to refer to the other is going to be important so I deemed this appropriate). When I try accessing a private variable from one class via using the pointer to the other and a getter function inside that, it works perfectly.
Problem: Using a setter (in this case, addPoints)/manipulating the variables however leads to no result.
I'm new so anything here might be "improper etiquette" and bad practice. Feel free to point them out! But please also try to provide a solution. This is also my first question on SO, so please be gentle!
Related code pieces:
Team.h
#include "Driver.h"
using namespace std;
class Team {
int Points = 0;
vector<Driver*> Drivers;
public:
void addPoints(int gained); //does not work
int getPoints(); //works perfectly
Driver getDriver(int nr);
void setInstance(vector<Driver*> drivers);
};
Team.cpp
#include "Team.h"
#include "Driver.h"
using namespace std;
void Team::addPoints(int gained) {
this->Points = this->Points + gained;
}
int Team::getPoints() {
return this->Points;
}
Driver Team::getDriver(int nr) {
return *Drivers[nr];
}
void Team::setInstance(vector<Driver*> drivers) {
this->Drivers = drivers;
}
Driver.h
using namespace std;
class Team;
class Driver {
int Points = 0;
Team* DriversTeam;
public:
void SetTeam(Team& team);
Team getTeam();
int getPoints(); //works
void addPoints(int gained); //doesn't work
};
Driver.cpp
#include "Driver.h"
#include "Team.h"
using namespace std;
void Driver::SetTeam(::Team& team) {
this->DriversTeam = &team;
}
Team Driver::getTeam() {
return *DriversTeam;
}
int Driver::getPoints() {
return this->Points;
}
void Driver::addPoints(int gained) {
this->Points = this->Points + gained;
}
Initializer.cpp (linking drivers to teams)
void InitializeData(vector<Team>& teams, vector<Driver> &drivers) {
//(...)
//reads each team in from data file to memory
//key part:
vector<Driver*> teamsDrivers;
for (auto& iter : drivers) { //this loop mainly determines which driver to link with which teams
if (iter.getName().compare(values[4]) == 0) { //values is csv line data in a string vector. I guess not the prettiest parsing method here but will be revised
teamsDrivers.push_back(&iter);
}else if(iter.getName().compare(values[5]) == 0) {
teamsDrivers.push_back(&iter);
}
}
tempTeam.setInstance(teamsDrivers);
teams.push_back(tempTeam);
}
(linking driver to team)
//drivers are linked to teams last, as they are declared first (so I cannot link them to the yet nonexisting teams)
void LinkTeam(vector<Driver>& drivers, vector<Team>& teams) {
for (auto& driverIter : drivers) { //iterate through drivers
for (auto& teamIter : teams) { // iterate through teams
bool found = 0;
for (size_t i = 0; i < teamIter.DriverAmount(); i++) {
if (driverIter.getName() == teamIter.getDriver(i).getName()) {
driverIter.SetTeam(teamIter);
found = 1;
break;
}
}
if (found) { //exit iterating if driver is found
break;
}
}
}
}
Example of use in main.cpp
teams[0].addPoints(10);
drivers[3].getTeam().addPoints(15); //driver 3 is linked to team 0
cout << teams[0].getPoints(); //15
cout << drivers[3].getTeam().getPoints(); //15
teams[0].getDriver(1).addPoints(20); //driver 1 of team 0=driver[3]
drivers[3].addPoints(25);
cout << drivers[3].getPoints(); //25
cout << teams[0].getDriver(1).getPoints(); //25
Thanks for the help in advance.
This is quite simple:
Your getTeam() and getDriver() functions are returning copies of the objects, not references, so the addPoints() are performed on temporary copies and not the real ones.
To fix it, simply change the return types to references (add &):
Team& getTeam();
and
Driver& getDriver();

Linkediting error when having a static unique_ptr [duplicate]

This question already has answers here:
Undefined reference to static class member
(9 answers)
Undefined reference to a static member
(5 answers)
Closed last year.
Because I want my unique_ptr to be the same in all my objects, I decided to make it a static field.
After that an error has appeared:
https://pastebin.com/PPe6z0Ub
I don't really know how to fix it, I've tried searching for it online but I couldn't find anything really useful.
Code:
DBFeed.h
#pragma once
#include <vector>
#include <string>
#include <memory>
class DBFeed
{
public:
void CalculatePosts();
std::vector<std::string> GetPost();
void ClearFeed();
private:
static std::unique_ptr<std::vector<std::vector<std::string>>> m_postari;
static int m_index;
};
DBFeed.cpp
#include "DBFeed.h"
#include "DBLink.h"
int DBFeed::m_index = 0;
void DBFeed::CalculatePosts()
{
DBFeed::m_postari = std::make_unique<std::vector<std::vector<std::string>>>();
pqxx::work worker(*DBLink::GetInstance());
try
{
worker.conn().prepare("CountPostsFeed", "SELECT COUNT(id) FROM posts");
worker.conn().prepare("ReadAllPostsFeed",
"SELECT message FROM followers RIGHT JOIN posts ON followers.followed = posts.user_id WHERE followers.follower = 51 LIMIT 5 OFFSET" + std::to_string(m_index+=5)
);
pqxx::row countPostsResult = worker.exec_prepared1("CountPostsFeed");
std::string number = countPostsResult.at("count").c_str();
pqxx::result readAllPostsResult = worker.exec_prepared_n(std::stoi(number), "ReadAllPostsFeed");
for (const auto& currentPost : readAllPostsResult)
{
std::string postID = currentPost.at("id").c_str();
std::string message = currentPost.at("message").c_str();
std::string dateCreated = currentPost.at("date_created").c_str();
DBFeed::m_postari->push_back(std::vector<std::string>{postID, message, dateCreated});
}
worker.commit();
}
catch (const pqxx::unexpected_rows&)
{
throw std::runtime_error("Reading all of an users posts for feed failed");
}
}
std::vector<std::string> DBFeed::GetPost()
{
if (m_postari->empty())
{
CalculatePosts();
}
std::vector<std::string> deReturnat = m_postari->at(0);
m_postari->erase(m_postari->begin());
return deReturnat;
}
void DBFeed::ClearFeed()
{
m_index = 0;
m_postari.reset();
}
Why is this error happening and how can I fix it?
//Edit:
Fixed it by adding this by changing DBFeed.cpp's first lines as follows:
#include "DBFeed.h"
#include "DBLink.h"
int DBFeed::m_index = 0;
std::unique_ptr<std::vector<std::vector<std::string>>>
DBFeed::m_postari = std::make_unique<std::vector<std::vector<std::string>>>();
void DBFeed::CalculatePosts()
{
pqxx::work worker(*DBLink::GetInstance());
....
But I'd still like to get an explanation on why it was happening and why is it fixed now.

c++ method parameters giving unexpected output

Main class code:
#include <iostream>
#include "Chair.h"
using namespace std;
int main()
{
cout << "Hello world!" << endl;
Chair c1;
c1.chairType("Olivia",4,32,true); // not working
Chair c2;
c1.chairType("Stephano",8,8,false);
return 0;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Header class code:
#ifndef CHAIR_H_INCLUDED
#define CHAIR_H_INCLUDED
#include <iostream>
using namespace std;
class Chair
{
private:
int legCount;
int height;
bool cushioned;
string name;
public:
void chairType(string newName, int newLegCount, int newHeight, bool cush);
};
#endif // CHAIR_H_INCLUDED
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Chair.cpp class:
#include <iostream>
#include "Chair.h"
using namespace std;
void Chair::chairType(string newName, int newLegCount, int newHeight, bool cush)
{
name=newName;
legCount=newLegCount;
newHeight=newHeight;
cushioned=cush;
cout<<"I'm a chair, the following are my specs: "<<endl;
cout<<"Model: "<<name<<endl;
cout<<"Num of Legs: "<<legCount<<endl;
cout<<"Height: "<<height<<endl;
cout<<"Cushioned? : "<<cush<<endl;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Output for the four variables fed into the method is as expected, apart from the third variable (second int) which is printing as being 2752192 regardless of what I feed to it, and for both objects c1 and c2.
I'm new to C++. I've been practising some object class questions trying to familiarise myself with the syntax. I vaguely understand pointers can cause reference addresses to print on occasion. However, this 7 digit number doesn't appear to be in address format. I've done some searches and can't see a similar question. If there is one, I would appreciate direction to it. I don't wish to break the terms of posting here on the site. Thank you in advance for your assistance.
newHeight=newHeight;
should be replaced with
height=newHeight;
but better you should initialize object in constructor, rather than separate method:
class Chair
{
private:
int legCount;
int height;
bool cushioned;
string name;
public:
Chair( const string &newName, int newLegCount, int newHeight, bool cush) :
legCount( newLegCount ),
height( newHeight ),
cushioned( cush ),
name( newName )
{
}
...
};
int main()
{
cout << "Hello world!" << endl;
Chair c1("Olivia",4,32,true); // works now
Chair c2("Stephano",8,8,false);
return 0;
}
this way you cannot have instance of your class uninitialized and your mistake also would be detected by compiler.
Here is the mistake in your implementation Chair.cpp:
newHeight=newHeight;
This is the correct:
height = newHeight;
The long number you get is the uninitialized value of member variable height in your Chair object.

Accessor Method to view private variable based on argument in a class in c++?

My problem is that I have many variables in my class and I want them to be accessed via an accessor method. Of course I could have several accessor functions to output my private variables but how can I make it so I can access any of them via an argument. My class:
class Character {
public:
void setAttr(string Sname,int Shealth,int SattackLevel,int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int outputInt(string whatToOutput) {
return whatToOutput //I want this to either be health, attackLevel or defenseLevel
}
private:
string name;
int health;
int attackLevel;
int defenseLevel;
};
Basically what I want to know is how do I return a private variable in regards to the outputInt function. Most OOP tutorials have one function to return each variable which seems like a very unhealthy thing to do in a large program.
C++ doesn't support what you try to accomplish: reflection or detailed runtime information about objects. There is something called "Run-Time Type Information" in C++, but it can't provide information about your variable name: the reason is because, in the compiled and linked binary this information (names of your variables) will not be necessarily present anymore.
However, you can accomplish something close to that, using i.e. std::unordered_map instead of plain integer variables. So it's possible to access values by their names, as strings.
Please consider the following code:
#include <string>
#include <iostream>
#include <unordered_map>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
values.insert(std::make_pair("health", Shealth));
values.insert(std::make_pair("attackLevel", SattackLevel));
values.insert(std::make_pair("defenseLevel", SdefenseLevel));
}
int outputInt(const string& whatToOutput) {
return values.at(whatToOutput);
}
private:
string name;
std::unordered_map<std::string, int> values;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.outputInt("health") <<std::endl;
std::cout << "Attack level: " << yourCharacter.outputInt("attackLevel") << std::endl;
std::cout << "Defense level: " << yourCharacter.outputInt("defenseLevel") << std::endl;
return 0;
}
It will output as expected:
Health: 10
Attack level: 100
Defense level: 1000
Another option without dependency on unordered_map would be, to use predefined static strings for your variable names and an array or vector for your values. So we could replace the class Character above with something like:
static std::string variableNames[3] = {
"health",
"attackLevel",
"defenseLevel"
};
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
variableValues[0] = Shealth;
variableValues[1] = SattackLevel;
variableValues[2] = SdefenseLevel;
}
int outputInt(const string& whatToOutput) {
int retVal = 0;
for (size_t i = 0; i < sizeof(variableNames)/sizeof(std::string); ++i) {
if (!whatToOutput.compare(variableNames[i])) {
retVal = variableValues[i];
}
}
return retVal;
}
private:
string name;
int variableValues[3];
};
And getting still same output. However, here you have to manage a list with all your variable names inside the string array manually - I don't like this solution and would prefer one of the others above personally.
Most common ways in C++ to handle such a design is to have seperate getHealth(), getAttackLevel(), getDefenseLevel() functions instead. However, this will miss one use-case, which is: if you want to let the user input a string, like i.e. "health" and display the corresponding variable then, you would need to write code by yourself to call the corresponding getXXX() function. If this is not a issue in your case, consider the following code which is much cleaner:
#include <string>
#include <iostream>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int getHealth() const { return health; }
int getAttackLevel() const { return attackLevel; }
int getDefenseLevel() const { return defenseLevel; }
private:
string name;
int health, attackLevel, defenseLevel;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.getHealth() <<std::endl;
std::cout << "Attack level: " << yourCharacter.getAttackLevel() << std::endl;
std::cout << "Defense level: " << yourCharacter.getDefenseLevel() << std::endl;
return 0;
}
One other unrelated advice: Instead of using string as parameter types for your functions, use const string& (const reference to string; see my example code above). This allows easier calling of your functions (they can be called directly with an string literal without the need to create additional variables in the calling code) and they will not make a additional unnecessary copy. The only copy then will take place at: name = Sname; (in your code two copies took place).
I don't know if it can be a good idea for you, but you can use a public typedef struct that you pass by reference and set your value.
class Character {
public:
//...
typedef struct allvalues{
string vname;
int vhealth;
int vattackLevel;
int vdefenseLevel;
}allvalues;
void getValues(allvalues& val){
val.vname = name;
val.vhealth = health;
val.vattackLevel = attackLevel;
val.vdefenseLevel = detenseLevel;
}
//...
};
//...
//somewhere in the code
Character myCarac;
//...
//Here how to use it
Character::allvalues values;
myCarac.getValues(values);

c++ program crashing because of if statment [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
My c++ program is crashing i think because of an if statement. I am using MinGW compiler and am given no errors. I have no idea as to why i am getting the error. The if statement in my generate function looks fine to me. Im comparing a string with an instance of a vector string.
here is the cpp code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include "Insultgenerator_0hl14.h"
using namespace std;
FileException::FileException(const string& m) : message(m){}
string& FileException::what(){ return message;}
NumInsultsOutOfBounds::NumInsultsOutOfBounds(const string& m) : message(m){}
string& NumInsultsOutOfBounds::what(){ return message;}
InsultGenerator::InsultGenerator(const InsultGenerator& ) {};
InsultGenerator::InsultGenerator(){};
void InsultGenerator::initialize() {
int cols(0);
srand ( time(NULL));
string words ;
string filename("InsultsSource.txt");
ifstream filetoread(filename.c_str());
if(filetoread.fail()){
throw FileException("File not read.");
}
while(filetoread >> words){
if(cols==0){
colA.push_back(words);
cols++;
} else if(cols==1){
colB.push_back(words);
cols++;
}else{
colC.push_back(words);
cols= cols -2;
}
}
//for (int i=0;i<50;i++){
// cout << " "<< colA[i];
//}
}
string InsultGenerator::talkToMe() const{
string Thou = "Thou";
string a= Thou + " " + colA[(rand()%50)] + " " + colB[rand()%50] + " " + colC[rand()%50] +"!" ;
//cout << a << endl;
return a;
};//end talkToMe
vector<string> InsultGenerator::generate(const int num){
if (num<0){
throw NumInsultsOutOfBounds("You must be insulted at least once");
} else if (num >10000 ){
throw NumInsultsOutOfBounds("You are being insulted too many times!");
}
vector<string> insultList;
string list;
for(int i=0; i<num;i++ ){
list = talkToMe();
if(list != insultList[i]){
//insultList.push_back(list);
//cout << insultList[i]<< endl;
}
}
return insultList;
};//end generate
//int InsultGenerator::generateAndSave(const string filename, const int n) const{
//};//end generateAndSave
int main(){
InsultGenerator ig;
ig.initialize();
ig.talkToMe();
ig.generate(10);
}
Here is the header file :
#ifndef INSULTGENERATOR_0HL14_H_
#define INSULTGENERATOR_0HL14_H_
#include <string>
#include <vector>
using namespace std;
class InsultGenerator{
public:
InsultGenerator();
InsultGenerator(const InsultGenerator&);
void initialize() ;
string talkToMe() const;
vector<string> generate(const int) ;
int generateAndSave (const string, const int) const;
private:
vector<string> colA;
vector<string> colB;
vector<string> colC;
};
class FileException{
public:
FileException(const string&);
string& what();
private:
string message;
};
class NumInsultsOutOfBounds{
public:
NumInsultsOutOfBounds(const string &);
string& what();
private:
string message;
};
#endif
As soon as you call the operator[] on your vector, you are trying to access an element of your vector. In this case the vector is empty, which cause an undefined behaviour.
if(list != insultList[i]){
Before trying to access your vector, make sure that this one is initialized with some values.
The index (i) you are looking for must be lower than the size of the vector insultList.size() (since the indexing start at 0)
You're declaring insultList to be of type vector<string>:
vector<string> insultList;
Then you're trying to access elements of insultList:
if(list == insultList[i]){
//insultList.push_back(list);
//cout << insultList[i]<< endl;
}
But nowhere in between do you actually add anything to insultList -- how many elements does it have? Trying to access insultList[i] refers to unallocated memory which is causing your program crash.