The following pertains to homework. Restraunt pet project type thing, task is to update it to use vectors. The issue I’m having is this:
This winds up causing a core segmentation fault, yet is able to retrieve all the information appropriately when I use valgrind.
void Table::partyCheckout(void)
{
if(status == SERVED)
{
cout << " ---------------- " << endl;
cout <<"Table: " << tableId << "\nParty Size: " << numPeople << "\nWaiter: " << waiter->getName() << "\nSummary: " <<endl;
order->requestSummary();
cout << "Total: " << endl;
order->requestTotal();
cout << " ---------------- " << endl;
status = IDLE;
}
else
{
cout << "Error: " << tableId << " ";
if(numPeople == 0)
{
cout << "No one is at this table." << endl;
}
else
{
cout << "This party hasn't been served." << endl;
}
}
}
Setup: I’m storing the waiters and the orders in vectors.
At runtime: when it does the waiter->getName() it complains that it’s an invalid read, and that the memory location has been free’d by vector via a deallocater.
My logic on the matter: It looks ahead and sees that the vector itself is not accessed again and so deallocates it. Since I do no more writing after this point, the memory location remains intact. When it tries to read the location it sees it has been free’d, hence invalid read but it still gets the appropriate data.
So my question then, I suppose is two fold:
Does this logic sound right?
What should I do to fix it?
#ifndef HW3_H
#define HW3_H
#include <vector>
#include "Table.h"
#include "Waiter.h"
class hw3
{
private:
vector<Table> tables;
vector<Waiter> waiters;
vector<Order> orders;
public:
void begin();
};
#endif
.cpp file, most of the allocation:
ifstream configFile("config.txt"); //This guy is for initializing things
string line;
Menu theMenu;
getline(configFile, line);
stringstream intMaker;
int t1;
int t2;
string temp;
string temp2;
string temp3;
while (true)
{
getline(configFile, line);
Tokenizer str(line, " \n");
if(line =="")
{
break;
}
else
{
temp = str.next();
temp2 = str.next();
intMaker << temp;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
intMaker << temp2;
intMaker >> t2;
intMaker.str("");
intMaker.clear();
tables.push_back(*(new Table(t1,t2)));
}
}
getline(configFile, line);
while (true)
{
getline(configFile, line);
Tokenizer name(line, " ");
string tabl = "";
//Siphon off the name and the tables.
temp = name.next();
tabl = name.next();
Tokenizer strink(tabl, ",\n");
int numTables = (int) tables.size();
Table * tabs[numTables];
t1 = 0;
int keepinTabs = 0;
while(true)
{
string temp2 = strink.next();
if (temp2 == "")
{
break;
}
else
{
intMaker << temp2;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
for(int i = 0; i < numTables; i++)
{
if(tables.at(i).getTableId() == t1)
{
tabs[keepinTabs] = &tables.at(i);
}
}
keepinTabs++;
}
}
waiters.push_back(*(new Waiter(temp, tabl, *tabs))); //Waiter(name, list of tables, and an array of table numbers.
for(int j = 0; j < keepinTabs; j++)
{
for(int i = 0; i < tables.size(); i++)
{
if(tabs[j]->getTableId() == tables[i].getTableId())
{
tables.at(i).assignWaiter(&(waiters.back()));
}
}
}
if(line == "")
{
break;
}
}
Multiple issues I can see:
This code dynamically allocates an object of type
Table, then pushes a copy of this object intotables, and then forgets the address of the dynamically allocated object – you’re leaking memory.As above, with
Waiterthis time.This takes the address of an object inside the vector. While legal, it’s extremely fragile.
std::vectorcan move its contents around in memory when it resizes (e.g. when you push into it).This (or similar code elsewhere) might be the cause of your segfault. Seeing as you’re allocating the objects dynamically, maybe you should declare your vectors to hold just pointers:
You would then do e.g.
tables.push_back(new Table(t1, t2));. Of course, you have to make sure todeletethe dynamically allocated objects when you remove them from the vectors. An alternative would be to use smart pointers, e.g.: