Code actually runs fine for me, but I have to submit it to someone, and in return I get an error which I cannot perceive.
The following error is:
munmap_chunk(): invalid pointer (core dumped)
The error appears to be occurring in method named: loadLuggage. I have also checked the code with Valgrind, but no possible leaks were detected. Perhaps I was not compiling it correctly.
#include <iostream>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <cstdlib>
#include <ctime>
using namespace std;
template<typename T>
int izbrisiVrsto(queue<T> &queue) {
int numberOfRemoved = 0;
while (!queue.empty()) {
queue.pop();
numberOfRemoved++;
}
return numberOfRemoved;
}
template<typename T>
int deleteStack(stack<T> &stack) {
int numberOfDeleted = 0;
while (!stack.empty()) {
stack.pop();
numberOfDeleted++;
}
return numberOfDeleted;
}
class Traveler {
private:
string name;
string surname;
int age;
string emso; //used as ID
public:
Traveler(const string &name, const string &surname, int age, const string &emso)
: name(name), surname(surname), age(age), emso(emso) {
}
~Traveler() {}
string getName() const {
return name;
}
void setName(const string &name) {
this->name = name;
}
string getSurname() const {
return surname;
}
void setSurname(const string &surname) {
this->surname = surname;
}
int getAge() const {
return age;
}
void setAge(int age) {
this->age = age;
}
string getEmso() const {
return emso;
}
void setEmso(const string &emso) {
this->emso = emso;
}
};
enum TravelClass {
ECONOMY,
BUSINESS
};
class Luggage {
private:
int luggageID;
public:
Luggage(int id) : luggageID(id) {}
~Luggage() {}
int getLuggageID() const {
return luggageID;
}
void setLuggageID(int id) {
this->luggageID = id;
}
};
class BoardingTicket {
private:
Traveler traveler;
TravelClass travelClass;
Luggage luggage;
public:
BoardingTicket(const Traveler &traveler, const TravelClass &pr, const Luggage &luggage)
: traveler(traveler), travelClass(pr), luggage(luggage) {
}
~BoardingTicket() {}
Traveler getTraveler() const {
return traveler;
}
void setTraveler(const Traveler &traveler) {
this->traveler = traveler;
}
TravelClass getTravelClass() const {
return travelClass;
}
void setTravelClass(TravelClass travelClass) {
this->travelClass = travelClass;
}
Luggage getLuggage() const {
return luggage;
}
void setLuggage(const Luggage &luggage) {
this->luggage = luggage;
}
};
class Plane {
private:
int id; //plane ID
public:
stack<stack<Luggage> > trunk; //stack of luggage on plane = all travelers luggage
private:
unsigned int maxNumberOfLuggage; //number of maxium luggage on the heap
public:
Plane(int id, unsigned int maxNumberOfLuggage) :
id(id),
maxNumberOfLuggage(maxNumberOfLuggage) {
}
~Plane() {}
//get/set metode
int getID() const {
return id;
}
void setID(int id) {
this->id = id;
}
unsigned int getMaxNumberOfLuggage() const {
return maxNumberOfLuggage;
}
void setMaxNumberOfLuggage(unsigned int maxNumberOfLuggage) {
this->maxNumberOfLuggage = maxNumberOfLuggage;
}
void loadLuggage(queue<Luggage> &luggages) {
//TODO: implementation
while (luggages.empty() == false) {
stack<Luggage> pallet; //certain number of luggage on pallet
for (int i = 0; i < this->maxNumberOfLuggage; i++) {
Luggage luggage = luggages.front();
pallet.push(luggage);
luggages.pop();
}
this->trunk.push(pallet); //loading in trunk
}
}
queue<Luggage> unloadLuggage() {
//TODO: implementation
queue<Luggage> unloadingLuggage;
while (trunk.empty() == false) {
stack<Luggage> pallet = trunk.top();
trunk.pop();
for (int i = 0; i < pallet.size(); i++) {
unloadingLuggage.push(pallet.top());
pallet.pop();
}
}
return unloadingLuggage; //HACK: dummy return
}
};
class Airline {
public:
queue<BoardingTicket> boardingPeople; //people waiting to board on a plane
queue<Luggage> unloadedLuggage;
Airline() {}
~Airline() {}
void split(queue<BoardingTicket> &travelers, queue<BoardingTicket> &businessTravelers,
queue<BoardingTicket> &economyTravelers) {
//TODO: implementation
while (travelers.empty() == false) {
BoardingTicket traveler = travelers.front(); //izbira prvega potnika
if (traveler.getTravelClass() == ECONOMY) {
economyTravelers.push(traveler);
} else if (traveler.getTravelClass() == BUSINESS) {
businessTravelers.push(traveler);
}
travelers.pop(); //traveler vkrcan
}
}
queue<BoardingTicket> merge(queue<BoardingTicket> &businessTravelers, queue<BoardingTicket> &economyTravelers) {
//TODO: implementation
queue<BoardingTicket> merged;
while (economyTravelers.empty() == false) {
BoardingTicket first = economyTravelers.front();
merged.push(first);
economyTravelers.pop();
}
while (businessTravelers.empty() == false) {
BoardingTicket first = businessTravelers.front();
merged.push(first);
businessTravelers.pop();
}
return merged; //HACK: dummy return
return queue<BoardingTicket>(); //HACK: dummy return
}
queue<BoardingTicket> edit(queue<BoardingTicket> &waitingQueue) {
queue<BoardingTicket> businessTravelers;
queue<BoardingTicket> economyTravelers;
split(waitingQueue, businessTravelers, economyTravelers);
return merge(businessTravelers, economyTravelers);
}
void opravilaPriLetu(queue<BoardingTicket> readyPassengers,
queue<Luggage> appliedLuggage,
Plane lt) {
if (boardingPeople.size() != 0)
izbrisiVrsto(boardingPeople);
if (unloadedLuggage.size() != 0)
izbrisiVrsto(unloadedLuggage);
boardingPeople = edit(readyPassengers);
lt.loadLuggage(appliedLuggage);
//flying to destination
unloadedLuggage = lt.unloadLuggage();
}
};
bool MergeExclusivelyInBusinessClass() {
queue<BoardingTicket> business;
int luggageID = 0;
Traveler pt1("Victor", "Candice", 25, "1111111111111");
TravelClass pr1 = BUSINESS;
Luggage k1(luggageID++);
BoardingTicket kzv1(pt1, pr1, k1);
business.push(kzv1);
Traveler pt2("Charles", "Sennet", 17, "1111111111112");
TravelClass pr2 = BUSINESS;
Luggage k2(luggageID++);
BoardingTicket kzv2(pt2, pr2, k2);
business.push(kzv2);
Traveler pt3("Marc", "Cooper", 18, "1111111111113");
TravelClass pr3 = BUSINESS;
Luggage k3(luggageID++);
BoardingTicket kzv3(pt3, pr3, k3);
business.push(kzv3);
Traveler pt4("Frank", "McLorre", 45, "1111111111114");
TravelClass pr4 = BUSINESS;
Luggage k4(luggageID++);
BoardingTicket kzv4(pt4, pr4, k4);
business.push(kzv4);
queue<BoardingTicket> economy;
queue<BoardingTicket> mergeExpected = business;
Airline ld;
queue<BoardingTicket> actuallyMerged = ld.merge(business, economy);
if (mergeExpected.size() != actuallyMerged.size()) {
cout << "Metoda merge() did not fulfill did not fullfill with correct number of passenger ("
<< (int) mergeExpected.size() << "), but with " << (int) actuallyMerged.size() << " travelers." << endl;
return false;
}
while (!mergeExpected.empty() && !actuallyMerged.empty()) {
BoardingTicket actual = actuallyMerged.front();
actuallyMerged.pop();
BoardingTicket expected = mergeExpected.front();
mergeExpected.pop();
Traveler expectedP = expected.getTraveler();
Traveler actualP = actual.getTraveler();
TravelClass expectedPR = expected.getTravelClass();
TravelClass actualyPR = actual.getTravelClass();
Luggage expectedK = expected.getLuggage();
Luggage actualyK = actual.getLuggage();
if (expectedP.getEmso() != actualP.getEmso() || expectedP.getAge() != actualP.getAge() ||
expectedP.getSurname() !=
actualP.getSurname() ||
expectedP.getName() !=
actualP.getName() || expectedPR != actualyPR ||
expectedK.getLuggageID() !=
actualyK.getLuggageID()) {
cout << "Metoda merge() did not fill up expected queue of merged travelers with travelers that were given."
<< endl;
return false;
}
}
return true;
}
int main(int argn, char **args) {
if (MergeExclusivelyInBusinessClass())
cout << "Method merge() is successful." << endl;
else
cout << "Method merge() failed." << endl;
return 0;
}
I have troubles comprehending an error, and I'm not really sure how to solve it. Any ideas?
EDIT 1
I have been notified that error could be caused by for loop itself, because queue/stack size is constantly changing, therefore it is recommended to use while loop instead.
EDIT 2
I have finally managed to discover where exactly the problems appear:
Errors_Image
Without any further information about the error, its probable the invalid pointer error is occurring in the for-loop of the loadLuggage function. The first line of the for-loop accesses the front element of the luggages queue without checking if the queue is empty. Therefore, if the variable "maxNumberOfLuggage" has been set to a value that is greater than the size of the queue, you will get an invalid pointer error. Try modifying the for-loop to:
for (int i = 0; i < this->maxNumberOfLuggage; i++) {
Luggage luggage = luggages.front();
pallet.push(luggage);
luggages.pop();
if(luggages.empty()) break; //add this line of code
}
This may solve your problem.
If not, please provide more information on the error.
Related
I have to finish a prompt tonight for my coding class, and I believe I am writing this incorrectly. I have reviewed other stackoverflow answers, but I still lack the understanding necessary to correctly solve this. This is part of a bigger project, so I have included all code in case another function is causing this error, but in my testing only the Ballot class is giving me errors.
In getVote, if the parameter is within the used portion of the array,
return the Voter pointer that corresponds with that position.
This is supposed to be tested with:
Ballot ballot1("WI-643UWO");
const Vote *vote3 = ballot1.getVote(2);
cout << vote3 << "\n";
//header file
pragma once
#include <string>
using namespace std;
class Election {
private:
string office;
string firstCanidiateName;
string secondCanidiateName;
public:
Election(string office2, string firstCanidiateName2, string secondCanidiateName2);
string getOffice() const;
string getCandidate1() const;
string getCandidate2() const;
};
class Vote {
private:
string vOffice;
string canidiateName;
bool voteMadeInPerson;
public:
Vote(string vOffice2, string canidiateName2, bool voteMadeInPerson2);
string getOffice() const;
string getCandidate() const;
bool wasInPerson() const;
};
class Ballot {
private:
string voterID;
int votesStored;
Vote* votePointer[6];
public:
Ballot();
Ballot(string voterID2);
~Ballot();
string getVoterId() const;
int getVoteCount() const;
const Vote* getVote(int votePosition) const;
void recordVote(string office, string candidateName, bool voteInPerson);
int countInPersonVotes();
int findVote(string office) const;
};
//functions file
#include "p3.h"
#include <string>
using namespace std;
Election::Election(string office2, string firstCanidiateName2, string secondCanidiateName2) {
office = office2;
firstCanidiateName = firstCanidiateName2;
secondCanidiateName = secondCanidiateName2;
}
string Election::getOffice() const {
return office;
}
string Election::getCandidate1() const {
return firstCanidiateName;
}
string Election::getCandidate2() const {
return secondCanidiateName;
}
string Vote::getOffice() const {
return vOffice;
}
string Vote::getCandidate() const {
return canidiateName;
}
bool Vote::wasInPerson() const {
return voteMadeInPerson;
}
Vote::Vote(string vOffice2, string canidiateName2, bool voteMadeInPerson2) {
if (vOffice2.empty() == true) {
vOffice2 = "Unknown";
}
vOffice = vOffice2;
if (canidiateName2.empty() == true) {
canidiateName2 = "Write In";
}
canidiateName = canidiateName2;
voteMadeInPerson = voteMadeInPerson2;
}
string Ballot::getVoterId() const {
return voterID;
}
int Ballot::getVoteCount() const {
return votesStored;
}
const Vote* Ballot::getVote(int votePosition) const {
Vote* out;
if (votePosition > -1 && votePosition < votesStored) {
//unsure if this is proper syntax -- will need testing
out = votePointer[votePosition];
return out;
}
else {
out = nullptr;
return out;
}
}
void Ballot::recordVote(string office, string candidateName, bool voteInPerson) {
if ((votesStored + 1) < 6) {
int x = findVote(office);
if (x != -1) {
Vote* z = new Vote(office, candidateName, voteInPerson);
votePointer[votesStored] = z;
++votesStored;
}
}
}
int Ballot::countInPersonVotes() {
int count = 0;
for (int i = 0; i < votesStored; ++i) {
bool x = false;
x = votePointer[i]->wasInPerson();
if (x == true) {
count++;
}
}
return count;
}
int Ballot::findVote(string office) const {
//test to make sure this logically works
int i = 0;
bool matchCheck = false;
for (i = 0; i < votesStored; ++i) {
if (votePointer[i]->getOffice() == office) {
matchCheck = true;
return i + 1;
}
}
if (matchCheck == false) {
return -1;
}
}
Ballot::Ballot(string voterID2) {
voterID = voterID2;
votesStored = 0;
}
Ballot::Ballot() {
voterID = "Invalid ID";
votesStored = 0;
}
Ballot::~Ballot() {
/**this is what the prompt asks for, technically.
the book details that this can be achieved in a more simple matter --
using the delete[] operator.
*/
for (int i = 0; i < 6; ++i) {
delete votePointer[i];
}
}
Any help would be appreciated - I am unsure where I am messing up here. I seem to be getting a lot of read access violation errors, but we haven't touched on debugging, so I'm not necessarily sure how to identify what I did wrong. Furthermore, my functions did seem to work initially until I tried fixing it, and now it gives me a read-error almost instantly, which is concerning. And lastly - I am new to pointers, so there is a very high chance I messed up there. Thanks for any advice.
I'm learning new operator and I have the next question:
I want to reserve new memory when I add a new subject and if I do this way I lose all the previus content of array.
So, how can I do this if i have to reserve memory each time that i want to add a new subject? Or in other words, how i reserve memory without lose the previus?
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
using namespace std;
class Subject {
public:
Subject() { m_name = "";
m_hours = 0;
}
string getName() { return m_name; }
int getHours() { return m_hours; }
void setName(string name) { m_name = name; }
void setHours(int hours) { m_hours = hours; }
private:
string m_name;
int m_hours;
};
class Person {
private:
string m_name;
int m_age;
Subject *m_subjects;
int m_nSubjects;
public:
Person() {
m_name = "";
m_age = 0;
m_nSubjects = 0;
}
~Person() {
}
string getName() { return m_name; }
int getAge() { return m_age; }
void setName(string name) {
m_name = name;
}
void setAge(int age) {
m_age = age;
}
void addSubject(string name, int hour);
void showSubjects();
};
void Person::addSubject(string name, int hours) {
m_subjects = new Subject[m_nSubjects+1]; *the problem is here, all the previus content is lost*
m_subjects[m_nSubjects].setName(name);
m_subjects[m_nSubjects].setHours(hours);
m_nSubjects++;
}
void Person::showSubjects() {
for (int i = 0; i < m_nSubjects; i++) {
cout << m_subjects[i].getName();
cout << "\n";
cout << m_subjects[i].getHours();
}
}
int main() {
int nSubjects;
string name;
int hours;
Person person1;
person1.setName("Name 1");
person1.setAge(30);
cout << "Subjects to add: ";
cin >> nSubjects;
for (int i = 0; i < nSubjects; i++) {
cout << "Name of subject: " << "\n" << endl;
cin >> name;
cout << "Hours: " << "\n" << endl;
cin >> hours;
person1.addSubject(name, hours);
}
person1.showSubjects();
system("pause");
return 0;
}
I hope you can understand me.
You need to copy the existing data to the new array before you then replace the previous array (which you are leaking, BTW), eg:
void Person::addSubject(string name, int hours) {
Subject *new_subjects = new Subject[m_nSubjects+1];
for(int i = 0; i < m_nSubjects; ++i) {
new_subjects[i] = m_subjects[i];
}
new_subjects[m_nSubjects].setName(name);
new_subjects[m_nSubjects].setHours(hours);
delete[] m_subjects;
m_subjects = new_subjects;
m_nSubjects++;
}
You also need to free the current array in your Person destructor to avoid leaking as well:
~Person() {
delete[] m_subjects;
}
And you also need to add a copy constructor and a copy assignment operator to Person as well, to avoid future problems with multiple Person objects sharing the same array in memory if you assign one Person to another:
Person(const Person &src) {
m_name = src.m_name;
m_age = src.m_age;
m_nSubjects = src.m_nSubjects;
m_subjects = new Subject[m_nSubjects];
for (int i = 0; i < m_nSubjects; ++i) {
m_subjects[i] = src.m_subjects[i];
}
}
Person& operator=(const Person &rhs) {
if (&rhs != this) {
Person copy(rhs);
std::swap(m_name, copy.m_name);
std::swap(m_age, copy.m_age);
std::swap(m_nSubjects, copy.m_nSubjects);
std::swap(m_subjects, copy.m_subjects);
}
return *this;
}
And, if you are using C++11 or later, you should (optionally) also add a move constructor and move assignment operator to Person, too:
Person(Person &&src) {
m_name = std::move(src.m_name);
m_age = src.m_age; src.m_age = 0;
m_nSubjects = src.m_nSubjects; src.m_nSubjects = 0;
m_subjects = src.m_subjects; src.m_subjects = nullptr;
}
Person& operator=(Person &&rhs) {
Person movedTo(std::move(rhs));
std::swap(m_name, movedTo.m_name);
std::swap(m_age, movedTo.m_age);
std::swap(m_nSubjects, movedTo.m_nSubjects);
std::swap(m_subjects, movedTo.m_subjects);
return *this;
}
See the Rule of 3/5/0 for more details.
A better solution is to use std::vector instead, let the compiler handle all of these details for you:
#include <iostream>
#include <string>
#include <vector>
#include <limits>
class Subject {
public:
Subject() {
m_name = "";
m_hours = 0;
}
Subject(std::string name, int hours) {
m_name = name;
m_hours = hours;
}
std::string getName() const { return m_name; }
int getHours() const { return m_hours; }
void setName(std::string name) { m_name = name; }
void setHours(int hours) { m_hours = hours; }
private:
std::string m_name;
int m_hours;
};
class Person {
private:
std::string m_name;
int m_age;
std::vector<Subject> m_subjects;
public:
Person() {
m_name = "";
m_age = 0;
}
std::string getName() const { return m_name; }
int getAge() const { return m_age; }
void setName(std::string name) { m_name = name; }
void setAge(int age) { m_age = age; }
void addSubject(std::string name, int hour);
void showSubjects() const;
};
void Person::addSubject(string name, int hours) {
m_subjects.push_back(Subject(name, hours));
}
void Person::showSubjects() const {
for (std::size_t i = 0; i < m_nSubjects.size(); ++i) {
cout << m_subjects[i].getName();
cout << "\n";
cout << m_subjects[i].getHours();
}
}
int main() {
int nSubjects;
std::string name;
int hours;
Person person1;
person1.setName("Name 1");
person1.setAge(30);
std::cout << "Subjects to add: ";
std::cin >> nSubjects;
for (int i = 0; i < nSubjects; i++) {
std::cout << "Name of subject: ";
std::getline(std::cin, name);
std::cout << "Hours: ;
std::cin >> hours;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
person1.addSubject(name, hours);
}
person1.showSubjects();
std::system("pause");
return 0;
}
This is my code:
#include<iostream>
#include<string.h>
using namespace std;
class Zichara
{
private:
char *name;
int price;
void copy(const Zichara &from)
{
name = new char[strlen(from.name) + 1];
strcpy(name, from.name);
price = from.price;
}
public:
Zichara(const char *name, int price) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->price = price;
}
Zichara(const Zichara &from)
{
copy(from);
}
~Zichara() {
delete [] name;
}
friend class PlaninarskiDom;
};
class PlaninarskiDom {
private:
char name[15];
int prices[2];
char star;
bool isZichara;
Zichara *zich;
void copy(const PlaninarskiDom &from) {
strcpy(name, from.name);
star = from.star;
isZichara = from.isZichara;
zich = from.zich;
for(int i = 0; i < 2; i++) {
prices[i] = from.prices[i];
}
}
public:
PlaninarskiDom(const char *name = "", int prices = 0, const char star = '\0') {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = 0;
this->prices[1] = 0;
}
PlaninarskiDom(const char *name, int *prices, const char star) {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = prices[0];
this->prices[1] = prices[1];
}
PlaninarskiDom(const PlaninarskiDom &from) {
copy(from);
}
~PlaninarskiDom() {
delete [] zich;
}
PlaninarskiDom& operator = (const PlaninarskiDom &from) {
if(this == &from) return *this;
delete [] zich;
copy(from);
return *this;
}
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
void operator --() {
if((int)star >= 65 && (int)star <= 70) {
++star;
if((int)star == 69) {
++star;
}
}
}
bool operator <= (char c) {
return star >= c;
}
void presmetajDnevenPrestoj(int day, int month, int &price) {
if(day < 0 || day > 31 || month < 0 || month > 12) {
throw 99;
}
else if(month >= 4 && month <= 8) {
price = prices[0];
}
else {
price = prices[1];
}
if(isZichara) {
price += zich->price;
}
}
friend ostream& operator << (ostream &, const PlaninarskiDom &);
};
ostream& operator << (ostream &os, const PlaninarskiDom &rhs) {
cout << rhs.name << " klasa:" << rhs.star << endl;
if(rhs.isZichara) {
cout << " so zichara" << endl;
}
return os;
}
int main(){
PlaninarskiDom p; //креирање на нов објект од класата планинарски дом
//во следниот дел се вчитуваат информации за планинарскиот дом
char imePlaninarskiDom[15],mestoZichara[30],klasa;
int ceni[12];
int dnevnakartaZichara;
bool daliZichara;
cin>>imePlaninarskiDom;
for (int i=0;i<2;i++) cin>>ceni[i];
cin>>klasa;
cin>>daliZichara;
//во следниот дел се внесуваат информации и за жичарата ако постои
if (daliZichara) {
cin>>mestoZichara>>dnevnakartaZichara;
PlaninarskiDom pom(imePlaninarskiDom,ceni,klasa);
Zichara r(mestoZichara,dnevnakartaZichara);
pom.setZichara(r);
p=pom;
}
else{
PlaninarskiDom *pok=new PlaninarskiDom(imePlaninarskiDom,ceni,klasa);
p=*pok;
}
//се намалува класата на планинарскиот дом за 2
--p;
--p;
int cena;
int den,mesec;
cin>>den>>mesec;
try{
p.presmetajDnevenPrestoj(den,mesec,cena); //тука се користи функцијата presmetajDnevenPrestoj
cout<<"Informacii za PlaninarskiDomot:"<<endl;
cout<<p;
if (p<='D')
cout<<"Planinarskiot dom za koj se vneseni informaciite ima klasa poniska ili ista so D\n";
cout<<"Cenata za "<<den<<"."<<mesec<<" e "<<cena; //се печати цената за дадениот ден и месец
}
catch (int){
cout<<"Mesecot ili denot e greshno vnesen!";
}
}
I ran a debugger on this code and it highlighted this:
name = new char[strlen(from.name) + 1];
This is the line of code as the line where the Seg Fault comes from.
This is an exercise for a class I have and I have to do it using dynamic memory allocation.
I've done this exact same thing many times before and there was no such error, so I have no idea why it is appearing, and I couldn't find an answer to this question on Google so far, so I apologize if somewhere out there it does exist.
Thanks everyone for the suggestions, this has been fixed!
You call this method:
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
but you never allocate zich so you invoke UB calling a method on nullptr
Note: your PlaninarskiDom::copy() is incorrect as well, as you just assign pointer from another object aka shallow copy, which will lead to multiple destruction, though most probably you did not hit this issue yet. You should do deep copy instead or use std::shared_ptr is you plan to share ownership. Anyway if you are not limited by conditions using smart pointers are preferable when dealing with dynamically allocated objects. Or using special containers like std::vector or std::string which do proper memory management for you.
I am relatively new to C++ and classes. When I pass a char* through to the class constructor and copy it into the m_make and m_model char*'s, they are still empty. They are not pointing to random bits of memory when I print them out, no data is outputted, just blank space.
Constructor:
RentalCar::RentalCar(int year, char * make, char * model, float price, bool available)
{
m_year = year;
myStringCopy(m_make, make);
myStringCopy(m_model, model);
m_price = price;
m_available = available;
}
EDIT:
void readFile(RentalAgencyADT * list, ifstream & file)
{
char letter;
char word[7];
int i = 0; //position in word
int j = 0; //position in RentalCar data
int k = 0; //position of line in RentalAgencyADT
int l = 0; //position of RentalAgencyADT
while((letter = file.get()) != EOF)
{
if(letter == ' ' || letter == '\n')
{
int year;
char make[7], model[7];
float price;
bool available;
i = 0;
if(k != 0)
{
switch(j)
{
case 0:
year = atoi(word);
j++;
break;
case 1:
myStringCopy(make,word);
j++;
break;
case 2:
myStringCopy(model,word);
j++;
break;
case 3:
price = atof(word);
j++;
break;
case 4:
available = (bool) atoi(word);
list[l].inventory[k - 1] = RentalCar(year,make,model,price,available);
j = 0;
k++;
break;
}
clearWord(word);
i = 0;
if(k == 7)
{
}
}
else if(k == 0)
{
switch(j)
{
case 0:
myStringCopy(list[l].name, word);
j++;
break;
case 1:
//intCopy((list[l].zipcode),word);
//cout << list[l].zipcode << endl;
for(int i = 0; i < 5; i++)
{
list[l].zipcode[i] = word[i] - '0';
cout << list[l].zipcode[i];
}
j = 0;
k++;
break;
}
clearWord(word);
}
if(j == 4)
{
clearWord(make);
clearWord(model);
}
}
else
{
word[i] = letter;
i++;
}
}
}
Here is the RentalCar.cpp file:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "RentalCar.h"
using namespace std;
char* myStringCopy(char * destination, char * source);
RentalCar::RentalCar(int year, char * make, char * model, float price, bool available)
{
m_year = year;
myStringCopy(m_make, make);
myStringCopy(m_model, model);
m_price = price;
m_available = available;
}
char* myStringCopy(char * destination, char * source)
{
int i = 0;
while(source[i] != '\0')
{
destination[i] = source[i];
i++;
}
destination[i] = '\0';
return destination;
}
int RentalCar:: getYear()
{
return m_year;
}
void RentalCar:: setYear(int year)
{
m_year = year;
}
char* RentalCar:: getMake()
{
return m_make;
}
void RentalCar:: setMake(char * make)
{
myStringCopy(m_make, make);
}
char* RentalCar:: getModel()
{
return m_model;
}
void RentalCar:: setMode(char * model)
{
myStringCopy(m_model, model);
}
float RentalCar:: getPrice()
{
return m_price;
}
void RentalCar:: setPrice(int price)
{
m_price = price;
}
bool RentalCar:: getAvailable()
{
return m_available;
}
void RentalCar::setAvailable(bool available)
{
m_available = available;
}
void RentalCar::print()
{
cout << m_year << " " << m_make << " " << m_model << ", $" << m_price << ", Available: " << boolalpha << m_available << endl;
}
float RentalCar::estimateCost(int days)
{
return m_price * days;
}
I was using the strcpy() function earlier just to test but it didnt work either.
Headerfile:
#ifndef RENTALCAR_H_
#define RENTALCAR_H_
class RentalCar
{
public:
RentalCar(const int year, char * make, char * model, const float price, bool available);
int getYear();
void setYear(int year);
char* getMake();
void setMake(char make[]);
char* getModel();
void setMode(char model[]);
float getPrice();
void setPrice(int price);
bool getAvailable();
void setAvailable(bool available);
void print();
float estimateCost(int days);
protected:
private:
int m_year;
char * m_make;
char * m_model;
float m_price;
bool m_available;
};
#endif
You are strcpy()-ing into un-initialized char * pointers, which is undefined behaviour.
At the least you should be using strdup(), e.g. m_make = strdup(make);, with a corresponding free() in the destructor.
Basically I have this
std::map<std::string, Location&> exits = std::map<std::string, Location&>();
As a private member in a class. And I am unsure about how I would delete it to free the memory when the object of the class gets deleted
I also have a lot of vectors like this
std::vector<Item> Ritems;
Which I am also unsure how to delete, the vector gets Objects& added to it
Deleaker gives me around 1000 of the following:
xmemory0, line 89 (c:\program files (x86)\microsoft visual studio 14.0\vc\include\xmemory0)
Location object
class Object;
class Location
{
public:
Location();
Location(std::string RoomName, std::string RoomDesc);
~Location();
Location(const Location& e);
void AddExit(std::string Direction, Location &Room);
void AddItem(Item &Items);
void AddObject(Object &Objects);
void RemoveObject(std::string ObjName);
void AddNPC(NPC &NPCs);
void PickUpItem(Character &CurChar, std::string ItemName);
void DisplayAll();
void DisplayExits();
void DisplayItems();
void DisplayObjects();
void DisplayNPCs();
std::string GetName();
std::string GetDesc();
Location GoCommand(std::string Direction);
void TalkCommand(std::string Communication, Character &MainCharacter);
Location operator=(const Location &other);
Object CheckObject(std::string Command, std::string ObjName);
private:
std::string Name;
std::string Description;
std::map<std::string, Location&> exits = std::map<std::string, Location&>();
std::vector<Item> Ritems;
std::vector<Object> Robjects;
std::vector<NPC> RNPC;
};
#include <iostream>
#include "Locations.h"
#include <regex>
#include "Object.h"
Location::Location()
{
Name = "";
Description = "";
}
Location::Location(std::string RoomName, std::string RoomDesc)
{
Name = RoomName;
Description = RoomDesc;
}
Location::~Location()
{
}
Location::Location(const Location& e)
{
Name = e.Name;
Description = e.Description;
exits = e.exits;
Ritems = e.Ritems;
Robjects = e.Robjects;
RNPC = e.RNPC;
}
void Location::AddExit(std::string Direction, Location &Room)
{
exits.insert(std::pair<std::string, Location*>(Direction, &Room));
}
void Location::AddItem(Item &Items)
{
Ritems.push_back(Items);
}
void Location::AddObject(Object &Objects)
{
Robjects.push_back(Objects);
}
void Location::RemoveObject(std::string ObjName)
{
Object Temp;
std::transform(ObjName.begin(), ObjName.end(), ObjName.begin(), ::tolower);
for (int i = 0; i < Robjects.size(); i++)
{
std::string TempS = Robjects[i].GetName();
std::transform(TempS.begin(), TempS.end(), TempS.begin(), ::tolower);
if (TempS == ObjName)
Robjects.erase(Robjects.begin() + i);
}
}
void Location::AddNPC(NPC &NPCs)
{
RNPC.push_back(NPCs);
}
void Location::PickUpItem(Character &CurChar, std::string ItemName)
{
std::transform(ItemName.begin(), ItemName.end(), ItemName.begin(), ::tolower);
for (int i = 0; i < Ritems.size(); i++)
{
std::string Temp = Ritems[i].GetName();
std::transform(Temp.begin(), Temp.end(), Temp.begin(), ::tolower);
if (Temp == ItemName)
{
CurChar.AddItem(Ritems[i]);
Ritems.erase(Ritems.begin() + i);
}
}
}
Object Location::CheckObject(std::string Command, std::string ObjName)
{
Object Temp;
std::transform(Command.begin(), Command.end(), Command.begin(), ::tolower);
std::transform(ObjName.begin(), ObjName.end(), ObjName.begin(), ::tolower);
for (int i = 0; i < Robjects.size(); i++)
{
std::string TempS = Robjects[i].GetName();
std::transform(TempS.begin(), TempS.end(), TempS.begin(), ::tolower);
if (TempS == ObjName)
return Robjects[i];
}
return Temp;
}
void Location::DisplayAll()
{
WriteLine(7, '-');
DisplayElement(7, Description);
DisplayExits();
DisplayItems();
DisplayObjects();
DisplayNPCs();
WriteLine(7, '-');
}
void Location::DisplayExits()
{
DisplayElement(7, "|- You can travel; ");
for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
{
SetColour(7);
std::cout << "\t";
SetColour(112);
std::cout << "[" << (*ii).first << "]";
SetColour(8);
std::cout << " to " << (*ii).second->GetName() << std::endl;
}
}
void Location::DisplayItems()
{
int Count = 0;
if (Ritems.size() != 0)
{
DisplayElement(7, "Items in room: ");
for (int i = 0; i < Ritems.size(); i++)
{
DisplayElementWC(Count, 5, 13, Ritems[i].GetName());
DisplayElementWC(Count, 6, 14, Ritems[i].GetDesc());
DisplayElementWC(Count, 6, 14, Ritems[i].GetItemValue());
Count++;
}
}
}
void Location::DisplayObjects()
{
int Count = 0;
if (Robjects.size() != 0)
{
DisplayElement(7, "Objects in room: ");
for (int i = 0; i < Robjects.size(); i++)
{
DisplayElementWC(Count, 5, 13, Robjects[i].GetName());
DisplayElementWC(Count, 6, 14, Robjects[i].GetDesc());
}
}
}
void Location::DisplayNPCs()
{
int Count = 0;
if (RNPC.size() != 0)
{
DisplayElement(7, "NPCs in room: ");
for (int i = 0; i < RNPC.size(); i++)
{
DisplayElementWC(Count, 5, 13, RNPC[i].GetName());
DisplayElementWC(Count, 6, 14, RNPC[i].GetDesc());
}
}
}
std::string Location::GetName()
{
return Name;
}
std::string Location::GetDesc()
{
return Description;
}
Location Location::GoCommand(std::string Direction)
{
Location ReturnLoc = *this;
std::string Test;
std::transform(Direction.begin(), Direction.end(), Direction.begin(), ::tolower);
for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
{
Test = (*ii).first;
std::transform(Test.begin(), Test.end(), Test.begin(), ::tolower);
if (Test == Direction)
ReturnLoc = *(*ii).second;
}
return ReturnLoc;
}
void Location::TalkCommand(std::string Communication, Character &MainCharacter)
{
std::string Test;
std::transform(Communication.begin(), Communication.end(), Communication.begin(), ::tolower);
for (int i = 0; i < RNPC.size(); i++)
{
Test = RNPC[i].GetName();
std::transform(Test.begin(), Test.end(), Test.begin(), ::tolower);
if (Test == Communication)
{
RNPC[i].StartConvo(MainCharacter);
}
}
}
Location Location::operator=(const Location &other)
{
Name = other.Name;
Description = other.Description;
exits = other.exits;
Ritems = other.Ritems;
Robjects = other.Robjects;
RNPC = other.RNPC;
return *this;
}
Okay I hope this is a MCVE aha
#include <iostream>
#include <map>
#include <regex>
#include <string>
#include <windows.h>
#include <cctype>
//Custom Classes
class Location;
class UpdateLocation
{
public:
UpdateLocation();
~UpdateLocation();
void AddLocation(Location &Room);
void UpdateNow(Location &Room);
Location GetLocal(Location &Room);
private:
std::map<std::string, Location*> Locations = std::map<std::string, Location*>();
};
class Location
{
public:
Location();
Location(std::string RoomName, std::string RoomDesc);
~Location();
Location(const Location& e);
void AddExit(std::string Direction, Location &Room);
void DisplayExits();
std::string GetName();
std::string GetDesc();
Location operator=(const Location &other);
private:
std::string Name;
std::string Description;
std::map<std::string, Location*> exits = std::map<std::string, Location*>();
};
UpdateLocation::UpdateLocation()
{
}
UpdateLocation::~UpdateLocation()
{
}
void UpdateLocation::AddLocation(Location &Room)
{
Locations.insert(std::pair<std::string, Location*>(Room.GetName(), &Room));
}
void UpdateLocation::UpdateNow(Location &Room)
{
for (std::map<std::string, Location*>::iterator ii = Locations.begin(); ii != Locations.end(); ++ii)
{
if ((*ii).first == Room.GetName())
{
*(*ii).second = Room;
}
}
}
Location UpdateLocation::GetLocal(Location &Room)
{
for (std::map<std::string, Location*>::iterator ii = Locations.begin(); ii != Locations.end(); ++ii)
{
if ((*ii).first == Room.GetName())
{
return *(*ii).second;
}
}
}
Location::Location()
{
Name = "";
Description = "";
}
Location::Location(std::string RoomName, std::string RoomDesc)
{
Name = RoomName;
Description = RoomDesc;
}
Location::~Location()
{
}
Location::Location(const Location& e)
{
Name = e.Name;
Description = e.Description;
exits = e.exits;
}
void Location::AddExit(std::string Direction, Location &Room)
{
exits.insert(std::pair<std::string, Location*>(Direction, &Room));
}
void Location::DisplayExits()
{
std::cout << "|- You can travel; " << std::endl;
for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
{
std::cout << "\t";
std::cout << "[" << (*ii).first << "]";
std::cout << " to " << (*ii).second->GetName() << std::endl;
}
}
std::string Location::GetName()
{
return Name;
}
std::string Location::GetDesc()
{
return Description;
}
Location Location::operator=(const Location &other)
{
Name = other.Name;
Description = other.Description;
exits = other.exits;
return *this;
}
void main()
{
//Create GameWorld
UpdateLocation UpdateIt;
Location HallWay("Hallway", "Long corridor with a wide array of footboats");
getchar();
getchar();
}
First, you probably want to read this (for c++03 and earlier):
Why Can't I store references in an STL map in C++?
For c++11 and later it's actually possible to have references as values in std::maps using std::map::emplace(), but it's inconvenient and I cannot see it being as useful as raw pointers, which also should be replaced with std::unique_ptrs if the container object owns the objects placed in it.
You probably want
std::map<std::string, Location *> exits;
as your private member. There's no need to delete your map nor your vector. When the destructor of your class is called, the destructor of the respective object is called. They basically self-destruct. You explained that the exits object doesn't own the Location objects, so exits shouldn't have anything to do with deallocating memory allocated for them.