Exception thrown: read access violation. when accessing pointer in array - c++

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)

Related

How do I change where the pointer is pointing to through a return statement?

I have a Player object which holds an ID string. I'm trying to check if a player already exists by iterating through a list of Players. If the player already exists, I want to return the existing player, else I will make a new instance of the Player object.
Player *playerExists(const std::string &playerId, const std::vector<Player>* players)
{
for (Player existingPlayer : *players)
{
if (existingPlayer.playerId == playerId)
{
std::cout << "Player " << existingPlayer.name << " exists" << std::endl;
return &existingPlayer;
}
}
return new Player();
}
The problem seems to be in the return statement. I don't know how to return the specific object to a pointer. This seems to be the only way I found not to get an error (talking about the & sing in the return statement).
Player* player = playerExists("SomeID", listOfPlayers);
listOfPlayers->push_back(*player);
delete player;
I'm quite new to using raw pointers so I probably just don't understand what the problem here is. I'd really appreciate if someone could explain what I'm doing wrong.
There are several issues with this code.
Each iteration of the loop is making a local copy of a Player in the vector, and thus will return a pointer to that copy if a match is found. But when the current iteration is finished, that copy is destroyed, so you will end up returning a dangling pointer. To fix that, your loop need to take a reference to each Player in the vector:
for (Player &existingPlayer : *players)
The next issue is if no match is found, you return a newed Player. The problem with that is the caller is then unconditionally deleteing the returned Player* regardless of whether it was newed or not. The vector owns the Player objects it is holding, so deleteing one of those objects is undefined behavior.
A better design choice is to have playerExists() return nullptr if no match is found. The caller can then do different things depending on whether a Player or a nullptr is returned, eg:
Player* playerExists(const std::string &playerId, const std::vector<Player>* players)
{
for (Player &existingPlayer : *players)
{
if (existingPlayer.playerId == playerId)
{
std::cout << "Player " << existingPlayer.name << " exists" << std::endl;
return &existingPlayer;
}
}
return nullptr;
}
Player* player = playerExists("SomeID", listOfPlayers);
if (player) {
// ID found, use player as needed...
listOfPlayers->push_back(*player); // why re-add a player that is already in the list???
} else {
// ID not found, do something else...
listOfPlayers->push_back(Player{}); // why add a blank player???
}
Different ways of tackling this. Biggest problem might be in this line:
for (Player existingPlayer : *players)
It's making a copy (I think) of a player already in the collection.
When you do a return &existingPlayer; ... well it's returning an object on the stack. Bad things will happen.
You are better off iterating the collection and returning an iterator, IMHO... Maybe...
std::vector<Player>::const_iterator playerExists(const std::string &playerId, const std::vector<Player>& players)
{
std::vector<Player>::const_iterator it = players.begin();
for (; it != players.end(); ++it)
{
if (it->playerId == playerId)
{
std::cout << "Player " << it->name << " exists" << std::endl;
break;
}
}
return it;
}
You can always test after the return for
With the returned iterator, you'll have to do something with it...
auto it = playerExists(playerId, players);
if (it == players.end())
{
// not found
} else {
// found
}
Your problem is there :
for (Player existingPlayer : *players)
In each iteration of the for loop, existingPlayer is a copy of the player that is stored in a local variable in the scope of the for loop. You are returning a pointer to a local variable which get destroyed after each loop iteration.
To avoid the copy, use a reference :
for (Player &existingPlayer : *players)
Here, existingPlayer is a reference to the real player. This is what you did with the const std::string in the function prototype.
I have also some suggestions to possibly improve your code :
Avoid raw C pointers, C++ give you tools to get the same functionnality in a (much) less error prone way and hence, more secure. If you don't need NULL as I see in your code, a reference is probably better. Else you should consider smart pointers (std::unique_ptr, std::shared_ptr. I would pass players by reference instead of pointers in your case.
std::vector may not be the best container. Choosing the right container can be difficult. Currently you are iterating over the whole array to find the player by his id. You should use a std::unordered_map<std::string,Player> that use a hash table and probably speed up lookup time. I would also use a typedef of std::a_container_class<Player> to avoid massive code rewrite if you change the container kind or write one from scratch later.
Does copying a Player make sense ? If not, explicitly delete copy constructor and copy assignment operator, the compiler will then throw an error if you want to copy the Player. Note that this is a design choice that I often do, multiple instance of the same player is normal depending on your objects design.
I'm doubtful about return new Player();. Why do you return a new player if no player exist ? With my personal interpretation (might be totally wrong), I would return an iterator. No pointer involved, you can "dereference" the iterator to get a reference to the found player and the non existence of player is signaled by return an iterator equal to players.end(). But beware a big drawback, be sure to test before modifying the container and invalidating iterators.
With my own design choices, I made a slightly untested and shorter version of your function :
#include <unordered_map>
typedef std::unordered_map<std::string,Player> PlayerCollection;
/* ... */
PlayerCollection::const_iterator playerExists(const std::string &playerId, const PlayerCollection &players)
{
return players.find(playerId);
}
Keep in mind that my suggestions are opinionated and are not the absolute truth. Read the other answers which have different ideas.

pointer returned to an object turns null after function returns address

I am new to CPP and I am writing a program as an assignment to simulate a train path system that includes destinations and starts using object oriented programming .
I have 2 classes as shown below (there is a a passenger class but it is not relevant ) :
class Train
{
public:
int cooldown_time;
int travel_time;
int time_since_movement;
int id;
class Station *start;
class Station *destination;
vector<Passenger *> current_passengers;
string status;
void add_train(vector<string> commands, vector<Station> stations, vector<Train> &trains)
{
travel_time = stoi(commands[THIRD_PART + 1]);
cooldown_time = stoi(commands[THIRD_PART + 2]);
status = TSTATUS1;
start = station_search(stations, commands[SECOND_PART]); // this is where the problem happens
destination = station_search(stations, commands[THIRD_PART]);
id = stations.size();
}
};
class Station
{
public:
int tuffy_price;
string city_name;
vector<Passenger *> current_passengers;
vector<Train *> current_trains;
int id;
void add_station(vector<Station> &stations, vector<string> &commands)
{
tuffy_price = stoi(commands[THIRD_PART]);
city_name = commands[SECOND_PART];
id = stations.size();
}
};
I have a search function dedicated to finding the start and destination based off a command that user enters for example :the user enters "add_train cityname1 cityname2 <cooldown_time> <travel_time>". my program detects the city names and searches a vector I have named stations with a key that is the city name and returns a pointer (because of the complications in memory behavior in a function , i set it to pointer) to that station-object .
the function is as below :
Station *station_search(vector<Station> stations, string key)
{
Station *dummy;
for (int i = 0; i < stations.size(); i++)
{
if (stations[i].city_name == key)
{
return &stations[i];
}
}
return dummy;
}}
my problem is with my search function's weird behavior , when I debug the program I see the function find the correct station object and return a pointer to it ,but when the execution returns to the constructor function it randomly (maybe not randomly ) turns the first pointer relating to the start station to null and replaces the values inside with garbage ones.
but after the function searches for the destination station it does not do this and the execution is correct.
Could someone explain why this error is occurring?
My guess is that I have not understood local variables and pointer returns well enough and I have committed a rookie mistake somewhere but I don't seem to find it .
PS: I did not include the full code as it's too long I can include it by attaching a file ,comment down if it's necessary.
Station *station_search(vector<Station> stations, string key)
If you take a closer look here, you will see that the stations parameter is passed by value, which means that after this function returns, this stations parameters will get destroyed. It will be no more. It will cease to exist. It will become an ex-parameter.
However this station_search returns a pointer to some value in this vector. Therefore, rules of logic dictate that it will return a pointer to a destroyed object. Attempting to dereference that pointer, in any way, becomes undefined behavior.
Your other class methods receive parameters by reference, so you must already understand the difference between passing parameters by value vs. by reference, so you should simply do the same here.
Here you are passing a copy of the vector, which is destroyed when the function returns. Additionally, if the key is not found an uninitialized pointer is returned.
Station *station_search(vector<Station> stations, string key)
{
for (Station &station : stations)
{
if (stations.city_name == key)
{
// Pointer becomes invalid when you leave.
// Accessing this pointer will cause undefined behavior.
return &station;
}
}
// This would always cause undefined behavior as dummy was not initialized.
return nullptr;
}
You should pass in a reference and initialize dummy:
Station *station_search(vector<Station> &stations, string key)

Holding a map reference to a vector of maps

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.

Assertion error when passing object by value -- it is my copy constructor?

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]));

Segmentation fault while accessing an object inside a vector of object

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. :)