I am having a segmentation fault while trying to access an object stored inside a vector. I have a Survey which consists of Processes. Each process consists of questions. So the Survey Object contains a vector or Processes and each process object contains a vector of questions. The class definitions are as follows:
class Survey {
private:
...
vector <Process> survey_processes;
....
public:
......
vector<Process> getSurveyProcesses()
{ return survey_processes; }
void addProcessObj(Process obj)
{ survey_processes.push_back(obj);}
.....
};
class Process
{
private:
....
vector<Question> proc_questions;
....
public:
...
vector<Question> getProcessQuestions()
{ return proc_questions;}
void addQuestionObj(Question obj)
{ proc_questions.push_back(obj); }
.....
};
class Question {
private:
int quesnum;
int answer;
...
public:
Question (int c_ques, int c_ans)
{
quesnum = c_ques;
answer = c_ans;
}
int getQuestionID()
{
return quesnum;
}
int getAnswer()
{
return answer;
}
...
};
As the new process object is created, I store it in the vector of Processes and for each Process Object, I push the Question Object in the vector of Questions. For the survey Object, I want to get each Process from the Process Vector and for each Process Object, get each question object and print it.
I can access the Process Objects and print them successfully by using following code.
cout << ((survey_obj.getSurveyProcesses()).back()).getProcessID() << endl;
When I try to extract the question object from inside the Process vector, it gives me a segmentation error. I believe I am making some syntax error while trying to access the object. How do I access the question Object embedded inside a vector of Questions for a given Process Object which is inside a vector of process objects for a given survey object?
Here is the relevant part of the code where the segmentation fault occurs.
int procnum = 0;
for (unsigned i = 11; i < all_words.size()-1; ++i)
{
vector<string> v;
string s = all_words.at(i);
stringstream ques_stream(s);
int ques_num;
ques_stream >> ques_num;
ques_stream.ignore();
// if process object already exists, do nothing. Otherwise create a new process object and add it to the survey object
if (procnum == ques_num)
;
else
{
Process proc_obj(ques_num);
survey_obj.addProcessObj(proc_obj);
procnum = ques_num;
}
string ques_strng;
ques_stream >> ques_strng;
ques_stream.ignore();
Question ques_obj(ques_strng);
// objective: put the new question object in the question vector of the last process object from the process vector of the survey object
cout << ((survey_obj.getSurveyProcesses()).back()).getProcessID() << endl;
Process current_proc_obj = (survey_obj.getSurveyProcesses()).back();
cout << " Current Process : " << current_proc_obj.getProcessID() << endl;
Question current_question_obj = (current_proc_obj.getProcessQuestions()).back();
((survey_obj.getSurveyProcesses()).back()).addQuestionObj(ques_obj);
**// this is where the segmentation fault occurs when i try to get the last object from process vector of the survey and for that object get the last element of the question vector. print the question id of this question object
cout << " Current Question : " << ((((survey_obj.getSurveyProcesses()).back()).getProcessQuestions()).back()).getQuestionID() << endl;**
cout << " Current Process Question : " << ((current_proc_obj.getProcessQuestions()).back()).getQuestionID() << endl;
}
I tried running the gdb debugger but it only tells me that error occurs while trying to access the questionID. I still do not know what i am doing wrong and any help would be greatly appreciated.
((survey_obj.getSurveyProcesses()).back()).addQuestionObj(ques_obj);
_______________copy^, _copy^ - ^_______added to copy
Since you are returning vectors by value, not reference, you are adding ques_obj to a temporary local vector, not the one held by survey_obj.
The crash is occurring because you're accessing past the end of the (empty) vector, since nothing got added to it.
One way to fix this is to return the class member vector by reference, instead of by value. (Since by value can be though of as a copy of the variable.)
class Survey {
private:
vector <Process> survey_processes;
public:
vector<Process>& getSurveyProcesses()//<--ampersand indicates return by reference
{ return survey_processes; }
};
Now, when you try this:
((survey_obj.getSurveyProcesses()).back()).addQuestionObj(ques_obj);
______^ this is the vector inside the Survey class,
not a copy
Fortunately, std::vector::back also returns by reference, so the ques_obj gets added to the object held by the vector, held by the Survey object - no local, temporary copies involved! Later, when you go to query that question, you'll find it in the place you expected it.
Two final notes: 1) You should decide whether you should also return the process_questions by reference; 2) If you had used the ability for vector to tell you how many elements it contains, instead of just assuming that back() would work, you would have found this problem earlier. :)
Related
I'm currently writing a program in c++ using recursion and I want to print out a vector of tuples that resides in a class member which has the same type as the class itself. Below, you can see the class "Data" which has a class member called "child" of the same type. It also has a vector of tuples I want to print out using the readTuples function.
class Data {
public:
vector<tuple<string, string, string>> myTuple;
Data *child;
void readTuples(){
for (int i = 0; i < myTuple.size(); i++)
{
std::cout << "ID: " << get<0>(myTuple[i]) << "\tTYPE: " << get<1>(myTuple[i]) << "\tVALUE: " << get<2>(myTuple[i]) << "\n";
}
}
}
In the function below, I receive the Data object as a parameter. I add a child to the Data object using the typecheck function which returns a data object with a filled vector of tuples. I then read the vector using the readTuples function. This works...
Data typecheck(Data data)
{
Data* child = new Data();
Data childData = statementList->typecheck(*child);
child = &childData;
data.child = child;
data.child->readTuples();
return data;
}
output
ID: a TYPE: integer VALUE: 1
ID: b TYPE: integer VALUE: 2
ID: c TYPE: integer VALUE: 3
The data object is then returned and caught in the object Data (i.e. the typecheck function has just been executed).
Data typecheck(Data data)
{
data = block->typecheck(data);
data.child->readTuples();
return data;
}
But when I try to read the vector of tuples again, it crashes. The command line returns weird symbols, so I presume this has something to do with pointers and memory allocation.
Thanks in advance.
Data typecheck(Data data)
{
Data* child = new Data();
Data childData = statementList->typecheck(*child);
child = &childData;
data.child = child;
data.child->readTuples();
return data;
}
childData is a local variable whose reference you take. Once this function terminates, childData is destroyed, and any references to it invalidated. At that point, data.child points to garbage, and dereferencing it is undefined behavior.
If you want the pointer to last longer than the current function, either return it, or allocate it on the heap and store a pointer to that.
My task is to construct a compiler which lexes, parses and analyses the resultant Abstract Syntax Tree to ensure type matching, avoid duplicate declaration etc.
It was instructed for us to construct a Symbol Table, which holds a map of variables and their types for each scope. I opted for a vector of maps. I preferred this over a stack since I can iterate over it when checking for variables at any scope.
I constructed Push, Pop, Lookup and Insert operations for this structure as shown below and my idea was to hold a reference to the latest map in the vector and add variables to it. As a new scope is entered a push operation is carried out creating a new map in the vector within which to store the arrays.
When a scope is exited a Pop operation is done to remove the map at the end of the vector and acquire the previous map which is now at the back of the vector.
Via debugging I've noticed the vector is simply holding no map details and working by reference seems to be doing nothing to update the vector that's supposed to be holding this map. How do I correctly reference a map inside a vector and maintain this structure?
Symbol Table:
struct SymbolTable {
// Stack defining scopes holding identifier / type details
std::vector<std::map<std::string,std::string>> _scopeVector;
// Tracks current working stack
std::map<std::string,std::string> _currentMap;
SymbolTable() = default;
void Push() {
std::map<std::string,std::string> *_tempMap;
_tempMap = new std::map<std::string,std::string>();
_scopeVector.push_back(*_tempMap);
_currentMap = _scopeVector.back();
}
void Insert(std::string p_name, std::string p_type) {
_currentMap.insert(std::make_pair(p_name,p_type));
}
// Returns type if found, empty if not
std::string Lookup (std::string p_name) {
for (int i = 0; i < _scopeVector.size(); i++) {
if (_scopeVector[i].find(p_name) == _scopeVector[i].end()) {
// No match yet
} else {
return _scopeVector[i].find(p_name)->first; // return var name
}
}
std::cerr << "Type name " << p_name << " not found in all of stack" << std::endl;
return "";
}
void Pop () {
_scopeVector.pop_back();
_currentMap = _scopeVector.back();
}
};
SymbolTable *ST;
Class constructor which sets up the Symbol Table:
SemanticAnalysisVisitor() {
ST = new SymbolTable();
ST->Push();
}
Debugger image of an empty vector but populated map
As for your problem (I think) the statement
_currentMap = _scopeVector.back();
copies the map from the vector.
_currentMap will always be a separate and distinct map, totally unrelated from whatever is in the vector.
It seems you want to use references, but that's not possible in this case (unless you do a redesign).
You could solve this problem (and the memory leak I mentioned in a comment) by having a vector of (smart) pointers to the maps, and make _currentMap a (smart) pointer as well.
I get an errors when trying to call a method in a class stored in collidersByLayer, this map is used to contain a vector of pointers, identified by the layer.
static map<int, vector<Collider*>> collidersByLayer;
//Called twice by both a player and a box
void AddCollider(Collider collider, int layer) {
//outputs either 640 for the player or 840 for the box
cout << collider.GetPosition().x << endl;
//checks if a layer already exists, if not make a new entry in the map
if (collidersByLayer.find(layer) == collidersByLayer.end()) {
collidersByLayer[layer] = vector<Collider*>();
}
//add the reference to the collider
collidersByLayer[layer].push_back(&collider);
//loop through the collidersByLayer map
for (auto const& x : collidersByLayer) {
vector<Collider*> colliders = x.second;
for (size_t c = 0; c < colliders.size(); c++) {
//the first time this runs fine, and outputs the position of the player (640).
//when this function is called for the second time,
//it gives me this error while trying to print the players position:
//Exception thrown: read access violation.
//__imp_sf::Transformable::getPosition(...) returned 0x44520010.
cout << colliders[c]->GetPosition().x << endl;
}
}
}
Your problem is here:
collidersByLayer[layer].push_back(&collider);
You are adding a pointer to a local variable to the collection. That object is destroyed when AddCollider returns.
The problem is at the line collidersByLayer[layer].push_back(&collider); You are pushing the address of Collider collider, which is a local object, into a static map. Local objects are destroyed whenever the scope they belong to ends. In other words, as soon as the function returns, that pointer is pointing to a destroyed object. If you ever call AddCollider again, you will attempt to read from dangling pointer which is undefined behavior.
It sounds like the Collider objects already exists and you just want to add their addresses to your map. In that case, you can simply make your function's argument a reference type. By doing so, you will be getting the addresses of the referred objects instead of those of the local copies of those objects. Try the following :
void AddCollider(Collider & collider, int layer)
everyone!
I just finished writing a 2-D maze (Class is an ADT titled "Maze"--how original) that uses dynamic memory allocation. I'm passing the Maze to a method of another class I've entitled "MazeSolver," which uses recursion and backtracking to solve the maze. Good news is my code compiles wonderfully when I pass the object by reference. News that I don't know if is good or bad is that I get an assertion error if I try to pass the Maze to MazeSolver by value.
Given that the error occurs only when I pass by value, I can only assume it has something to do with my copy constructor. Before going any further, here's some info on the code:
Maze is composed of squares. Each square is represented by a struct called SquareData.
struct SquareData
{
//data fields for the struct (NO POINTERS)
}
I've decided to represent the entire maze with a vector of SquareData pointers (this vector is in private section of the class "Maze").
vector<SquareData*> squares;
Implementation of my destructor looks like this (that last call referencing a Player class is just eliminating a dangling pointer I have declared as a static variable for that class, which I have pointing at the maze. I don't think it's important considering the question, but I am new to C++ after all and one of you may think it might be, so I've included it for "hmmms"):
// clears maze of its contents
void Maze::clear() {
int totalSquares = squares.size();
for (int loopVar = 0; loopVar < totalSquares; loopVar++)
{
delete squares[loopVar]; // deallocate memory by deleting the square structure
squares[loopVar] = nullptr; // eliminate dangling pointer
} // vector takes care of itself
} // end clear
Maze::~Maze(){
//clear the maze of contents (vector is full of pointers whose memory is on the heap)
clear();
//vector safe to deallocate itself now
Player::setMaze(nullptr); // remove the pointer from player
}
I've declared the copy constructor in header as follows:
/** Copy Constructor */
Maze(const Maze& myMaze);
with attempted implementation:
/** copy constructor */
Maze::Maze(const Maze& myMaze){
/** Initialize Constants */
mazeLength = myMaze.mazeLength;
mazeWidth = myMaze.mazeWidth;
exitRow = myMaze.exitRow;
exitCol = myMaze.exitCol;
entRow = myMaze.entRow;
entCol = myMaze.entCol;
/** copy the vector of pointers*/
for (int loopVar = 0; loopVar < myMaze.squares.size(); loopVar++)
{
squares.push_back(myMaze.squares[loopVar]);
}
} // end copy constructor
Here's how I attempted to understand what the problem was doing:
I wrote this vector display function in for my Maze class.
void Maze::vectorDisplay() const {
for (int loopVar = 0; loopVar < squares.size(); loopVar++)
{
cout << "Vector Index: " << loopVar << endl;
cout << "Pointer: " << squares[loopVar] << endl;
cout << "Row: " << squares[loopVar]->Row << endl;
cout << "Col: " << squares[loopVar]->Col << endl;
cout << "State: " << squares[loopVar]->State << endl;
}
} //end vectorDisplay
And found that the vector displays correctly when doing the following in the driver:
Maze myMazeObject(// parameters);
myMazeObject.vectorDisplay();
and will produce output with no complaints.
But now if I try to use code like this when passing by value:
Maze myMazeObject(// parameters);
MazeSolver myMazeSolver;
myMazeSolver.someMazeSolverMethod(myMazeObject);
where someMazeSolverMethod has the line myMazeObject.vectorDisplay();I get an assertion error just as the final element in the vector is being printed.
I want to say this is my fault and my copy constructor is a p.o.s. If any insight, please let me know how to fix it and what I can do in the future!
Thanks for taking the time to read and even more so to answer should you choose to!
-J
This is your problem.
squares.push_back(myMaze.squares[loopVar]);
Basically each Maze has a vector full of the same pointers. When one copy of the maze goes out of scope it will delete all the pointers. Thus the other Maze now has a set of invalid pointers.
Couple of solutions.
Don't use pointers.
Unless you SquareData is polymorphic there seems no reason to keep pointers.
std::vector<SquareData> squares;
If you want each copy of the maze to refer to the same squares.
Then use a shared pointer. This will keep a count of the number of references to each SquareData and thus only delete them when they truly go out of scope.
std::vector<std::shared_ptr<SquareData>> squares;
Least attractive (and probably not needed).
Change the code to actually copy the pointer content into a new object.
squares.push_back(new SquareData(myMaze.squares[loopVar]));
Use of
squares.push_back(myMaze.squares[loopVar]);
in the copy constructor will lead to problems downstream.That will be vaild had the contents of squares been objects not pointers.
There are now two objects holding on to the pointers. Both willl try to call delete on the same pointer, which easily leads to undefined behavior.
You can fix the problem by:
Using a vector objects instead of a vector of pointers, or
Creating new objects from the heap and adding them to the new object.
squares.push_back(new SquareData(*myMaze.squares[loopVar]));
I am dealing with a task to create a troop of bunnies where they can multiply at each round. So I define a class of Bunny (individual), and then define a class of Troop with a vector point to different bunnies.
My problem is, every time I use new to create an object Bunny in a loop, it will come out an error says:
"Debug assertion failed!!...vector iterator not incrementable..."
Here is a sample of my code:
class Bunny {
private:
string sex;
string color;
string name;
int age;
public:
string getname() { return name;};
Bunny(); // constructor
};
class Troop {
private:
vector<Bunny *> bunpointer;
vector<Bunny *>::iterator it;
public:
void newbunny();
void multiply();
};
void Troop::newbunny() {
Bunny * bun; // pointer to the Bunny class
bun = new Bunny;
cout << "Bunny " << bun->getname() << " is born! \n";
bunpointer.push_back(bun);
}
void Troop::multiply() {
it = bunpointer.begin();
while(it!=bunpointer.end()) {
cout << (*it)->getname() << " gave a birth. ";
newbunny();
++it;
}
it = bunpointer.begin();
}
So if I create 5 bunnies at the beginning, and call function Troop::multiply, there should be 10 bunnies. An interesting observation is, the error will occur after 2 bunnies being born.
I think the problem may lie in the use of new to create new objects in a iterator loop. The new may somehow interrupt the iterator pointer *it. But I am not sure if this is the case, and if it really is, how to deal with this.
modified: so it is actually a problem of using push_back(), which will probably invalidate the iterator!!
Thank you in advance!!
1) Unless you have a reason to, your code does not need to use new at all. The code becomes easier, and no chance of memory leaks. Also, I don't see the need for an iterator member in the Troop class, unless you can justify the reason for it.
2) As to your immediate problem, just use a non-iterator reliant loop. In other words, a simple loop that goes from 0 to the number of current bunnies, less 1.
Here is an example:
#include <vector>
//...
class Troop {
private:
std::vector<Bunny> bunpointer;
public:
void newbunny();
void multiply();
};
void Troop::newbunny() {
bunpointer.push_back(Bunny());
}
void Troop::multiply() {
size_t siz = bunpoiner.size();
for (size_t i = 0; i < siz; ++i ) {
newbunny();
cout << (*it)->getname() << " gave a birth. ";
}
}
The newbunny() function simply creates a Bunny() using a default constructor and adds the item to the vector.
If you want to use a container that doesn't invalidate iterators when inserting items, then you can use a std::list as opposed to a std::vector.
It appears that you are trying to modify the std::vector while iterating over it. This is generally not a good idea, for a variety of reasons.
In particular, when you call newbunny() inside the iterator's loop, it is possible that the iterator you used to hold will be invalidated, because the vector may be resized during the push_back.
See this question for details.
As mentioned by others, the push_back() is your culprit, not the new.
One way to palliate would be this:
size_t const max(bunpointer.size());
for(size_t i(0); i < max; ++i)
{
cout << bunpointer[i]->getname() << " gave a birth. ";
newbunny();
}
This works because you are only adding new bunnies at the end of your existing vector. These new bunnies are not taken in account by the loop (max doesn't change because you call newbunny()...) and the [i] access makes use of the vector in its current state.
That loop would not work if you were deleting items...
As a side note: the name "bunpointer" is not very clear... it's not a pointer, it's a vector of pointers.