Assign address to pointer inside struct - c++

I am trying to implement a path-finding algorithm.
So i have a 2d array with structs in it, and would like to follow the
track of the best opinion from one location to another. Therefore i try to work with structs (easy data handling) and pointer to other structs.
This is how it works in principle.
struct location{
int x;
int y;
location* parent;
};
int main(){
map_inf current;
vector<map_inf> allData;
someData = getData(); // returns vector of structs
current = someData[0];
while(current.x != 15 && current.y != 30){
for(int i = 1; i < someData.size(); i++){
someData[i].parent = &current;
allData.push_back(someData[i]);
}
someData = getData(); // get new data
current = someData[0];
}
for(int i=0; i<allData.size(); i++){
///////////////////////////////////////
// ALL PARENT POINTERS ARE EQUAL. WHY ?
///////////////////////////////////////
}
}
When i view my code with the debugger i can see that the "current"-element is correct and the pointers will be set properly. But when "someData" get fully processed and there is new data all previous parent pointers in allData also get updated.

You should increament/update the current pointer after the end of the for loop or in the for loop. You just used current = someData[0]; at the end of the for loop which means the current will contain the same pointer pointed by someData[0].

Related

Adding a new instance of an array to a vector

This is a continuation of my previous question: Nested vector<float> and reference manipulation.
I got the loops and all working, but I'm trying to add new instances of arrays to a total vector.
Here's one example of what I mean:
array<float, 3> monster1 = { 10.5, 8.5, 1.0 };
// ...
vector<array<float, 3>*> pinkys = { &monster1};
// ...
void duplicateGhosts() {
int count = 0;
int i = pinkys.size(); // this line and previous avoid overflow
array<float, 3>& temp = monster1; // this gets the same data, but right now it's just a reference
for (auto monster : pinkys) { // for each array of floats in the pinkys vector,
if (count >= i) // if in this instance of duplicateGhosts they've all been pushed back,
break;
pinkys.push_back(&temp); // this is where I want to push_back a new instance of an array
count++;
}
}
With the current code, instead of creating a new monster, it is adding a reference to the original monster1 and therefore affecting its behavior.
As mentioned in a comment you cannot insert elements to a container you are iterating with a range based for loop. That is because the range based for loop stops when it reaches pinkys.end() but that iterator gets invalidated once you call pinkys.push_back(). It is not clear why you are iterating pinkys in the first place. You aren't using monster (a copy of the elements in the vector) in the loop body.
The whole purpose of the loop seems to be to have as many iterations as there are already elements in the container. For that you need not iterate elements of pinkys but you can do:
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
// add elements
}
Further, it is not clear why you are using a vector of pointers. Somebody has to own the monsters in the vector. If it isnt anybody else, it is the vector. And in that case you should use a std::vector<monster>. For shared ownership you should use std::shared_ptr. Never use owning raw pointers!
Don't use a plain array for something that you can give a better name:
struct monster {
float hitpoints; // or whatever it actually is.
float attack; // notice how this is much clearer
float defense; // than using an array?
};
With those modifications the method could look like this:
void duplicateGhosts() {
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
pinkys.push_back( pinkys[i] );
}
}
From the name of the method I assumed you want to duplciate the vectors elements. If you want to just add the same monster as many times as there were elements before, that is
void duplicateGhosts() {
auto old_size = pinkys.size();
for (size_t i=0; i < old_size; ++i) {
pinkys.push_back( monster{} );
}
}

How can I add elements to a vector inside of a vector when both vectors are dynamically allocated?

Here is a very brief description of the project im doing:
I currently have it set up as a vector containing a vector of structs. It can be a vector containing a queue of structs if that would make this easier as the elements will be unloaded FIFO.
I just need to sort the main vector in order of vector/queue containing the most structs.
Here is my code:
MetaV.push_back(vector<sData>()); //create vector inside vector
//load data into structs
metaV.back().push_back(item); //push struct onto the vector inside the vector
//loop struct portion until process changes, then loop to top
MetaV is declared as:
std::vector<std::vector<sData>>metaV;
sData is the struct and is an object? of that struct declared as:
sData item;
Later in the code I can access all elements in the struct in metaV, however instead of being (in the instance of the file) 3 vectors with 14 structs throughout them, MetaV just contains 17 items.
So my question is, how do I add the structs into the dynamically made vectors inside of the vector?
Where is my code wrong?
I thought back() added to the last element, but I guess it adds to the back of it, not inside of it?
I tried to put as little code as possible as I know my error is in those two lines. I can provide more if needed.
Thanks
EDIT: here is the snippet of code if this makes it more complete and verifiable.
item.ident = mcode;
item.desc = mdesc;
item.cycle = mcyc;
item.ncycle = newCycle;
item.tasks = codeDesc;
item.taskEnd = codeEnd;
item.procNum = numProcess;
metaV.push_back(vector<sData>());
//if new process, store and reset counts
if (n != numProcess)
{
//create new vector in metaV and push onto it
metaV.push_back(vector<sData>());
metaV.back().push_back(item);
if(sched_code == "PS")
{
taskTot = io_count;
io_count = 0; //reset count for next process
}
else if(sched_code == "SJF")
{
taskTot = io_count + taskNum;
io_count = 0;
taskNum = 0; //reset counts
}
else if (sched_code == "FIFO")
{
//do nothing
}
else
{
cout << "Scheduling Code Error: " << sched_code << endl;
}
countz.proNum = n;
countz.taskNum = taskTot;
//push onto vector to be sorted
procSort.push_back(countz);
n = numProcess;
}
else //if n == numProcess
{
metaV.back().push_back(item); //push struct into vector, in vector metaV
}

c++ 2d array of class pointers

i am trying to create a 2d array holding pointers of my class. first, i'd like to assign all of them NULL:
Timetable::Timetable(int hours) : TimetableBase(hours){
scheduledLectures = new Lecture**[5];
for (int i = 0; i < 5; i++) {
scheduledLectures[i] = new Lecture*[hours];
for (int j = 0; j < hours; j++)
scheduledLectures[i][j] = NULL;
};
}
this is for a timetable generator application. i have a function to set these pointers to a specific object.
void Timetable::setLecture(Lecture& lecture){
while ((lecture.getDuration()) -1 > 0){
scheduledLectures[lecture.getDayScheduled()][(lecture.getHourScheduled())+1] = &lecture;
}
}
the compiler returns no errors for this, but when its running, it seems that the pointers remain NULLs.
i am sure the error is inside the setter function (and almost sure that its a grammar mistake) but i cannot find the solution for that.
whats wrong in here?
thank you
Use a vector (or std::array) of pointers or shared_ptrs (or unique_ptrs depending on how your lifetimes are arranged) instead of a 2D array of pointers that you manage yourself. Save yourself the trouble of managing the memory and lifetimes of your objects manually.
class TimeTable {
vector<vector<shared_ptr<Lecture>>> scheduledLectures;
};
Timetable::Timetable(int hours)
: TimetableBase(hours),
scheduledLectures(5, vector<shared_ptr<Lecture>>(5)) {}
void Timetable::setLecture(std::shared_ptr<Lecture> lecture){
while ((lecture->getDuration()) -1 > 0) { // not sure what this does
scheduledLectures[lecture->getDayScheduled()][(lecture->getHourScheduled())+1] = lecture;
}
}
You can test whether a shared_ptr is null like follows
auto s_ptr = std::shared_ptr<int>{}; // null
// either assign it to a value or keep it null
if (s_ptr) {
// not null
}
If you are managing the memory of the Lecture objects elsewhere then just use a 2D vector of pointers and trust your code
class TimeTable {
vector<vector<Lecture*>> scheduledLectures;
};
Timetable::Timetable(int hours)
: TimetableBase(hours),
scheduledLectures(5, vector<Lecture*>(5)) {}
void Timetable::setLecture(Lecture& lecture){
while ((lecture.getDuration()) -1 > 0) { // not sure what this does
scheduledLectures[lecture.getDayScheduled()][(lecture.getHourScheduled())+1] = &lecture;
}
}

Copy elements of an old array of pointers into new array of pointers?

I need some assistance with a C++ project. What I have to do is remove the given element from an array of pointers. The technique taught to me is to create a new array with one less element and copy everything from the old array into the new one except for the specified element. After that I have to point the old array towards the new one.
Here's some code of what I have already:
I'm working with custom structs by the way...
Data **values = null; // values is initialized in my insert function so it is
// populated
int count; // this keeps track of values' length
bool remove(Data * x) {
Data **newArray = new Data *[count - 1];
for (int i = 0; i < count; i++) {
while (x != values[i]) {
newArray[i] = values[i];
}
count -= 1;
return true;
}
values = newArray;
return false;
}
So far the insert function works and outputs the populated array, but when I run remove all it does is make the array smaller, but doesn't remove the desired element. I'm using the 0th element every time as a control.
This is the output I've been getting:
count=3 values=[5,6,7] // initial insertion of 5, 6, 7
five is a member of collection? 0
count=3 values=[5,6] // removal of 0th element aka 5, but doesn't work
five is a member of collection? 0
count=4 values=[5,6,5] // re-insertion of 0th element (which is stored in
five is a member of collection? 0 // my v0 variable)
Could anyone nudge me in the right direction towards completing this?
First of all, your code is leaking memory like no good! Next you only copy the first element and not even that if the first element happens to be the one you want to remove. Also, when you return from your function, you haven't changed your internal state at all. You definitely want to do something along the lines of
Data** it = std::find(values, values + count, x);
if (it != values + count) {
std::copy(it + 1, values + count, it);
--count;
return true;
}
return false;
That said, if anybody taught you to implement something like std::vector<T> involving reallocations on every operation, it is time to change schools! Memory allocations are relatively expensive and you want to avoid them. That is, when implementing something like a std::vector<T> you, indeed, want to implement it like a std::vector<T>! That is you keep an internal buffer of potentially more element than there are and remember how many elements you are using. When inserting a new element, you only allocate a new array if there is no space in the current array (not doing so would easily result in quadratic complexity even when always adding elements at the end). When removing an element, you just move all the trailing objects one up and remember that there is one less object in the array.
Try this:
bool remove(Data * x)
{
bool found = false;
// See if x is in the array.
for (int i = 0; i < count; i++) {
if (x != values[i]) {
found = true;
break;
}
}
if (!found)
{
return false;
}
// Only need to create the array if the item to be removed is present
Data **newArray = new Data *[count - 1];
// Copy the content to the new array
int newIndex = 0;
for (int i = 0; i < count; i++)
{
if (x != values[i])
newArray[newIndex++] = values[i];
}
// Now change the pointers.
delete[] values;
count--;
values = newArray;
return true;
}
Note that there's an underlying assumption that if x is present in the array then it's there only once! The code will not work for multiple occurrences, that's left to you, seeing as how this is a school exercise.

How to resolve a bad_alloc that seems unlikely to be an out-of-memory issue?

I'm writing a bit of code for searching a maze with BFS in C++ (my primary language is Python, but I wanted to excersise my C++ brain a bit...), and I stumbled across this strange error.
Here are the relevant data structures:
struct Maze {
std::pair<int, int> start;
std::pair<int, int> goal;
std::pair<int,int> dims;
std::set<std::pair<int, int> > passable;
};
struct SearchNode {
std::pair<int, int> cell;
Maze* pMaze;
SearchNode* parent;
std::vector<SearchNode*> children;
};
Assume that I've already got a method void parseFile(Maze* maze, char* filename) that reads in a maze text file, storing the (row, col) pairs of the start and goal squares as well as a set corresponding to the (row, col) pairs that are "passable" in the maze.
There are a few other functions as well:
bool isPassable(Maze* maze, std::pair<int,int> testCell);
std::vector<SearchNode*> getPassableChildren(SearchNode sn);
void mazeSearch(Maze* maze);
Here are their implementations:
// <...snip...>
inline bool isPassable(Maze* maze, std::pair<int,int> cell) {
return maze->passable.find(cell) != maze->passable.end();
}
std::vector<SearchNode*> getPassableChildren(SearchNode sn) {
// Store a cached copy of the children, so if we require multiple queries
// we do not have to re-compute children.
if(sn.children.empty()) {
Maze* mazePointer = sn.pMaze;
int r = sn.cell.first;
int c = sn.cell.second;
for(int i = 0; i <= 2; ++i) {
for(int j = 0; j <= 2; ++j) {
if (!(i == 1 && j == 1)) {
std::pair<int,int> childCell(r+i-1, c+j-1);
if(isPassable(mazePointer, childCell)) {
// Build child SN
SearchNode child;
child.cell = childCell;
child.parent = &sn;
child.pMaze = mazePointer;
sn.children.push_back(&child);
}
}
}
}
}
return sn.children;
}
void mazeSearch(Maze* maze) {
std::set<std::pair<int,int> > visited;
std::deque<SearchNode> workQueue;
// Create root node.
SearchNode root;
root.cell = maze->start;
root.parent = NULL;
root.pMaze = maze;
workQueue.push_back(root);
visited.insert(root.cell);
while(!workQueue.empty()) {
SearchNode sn = workQueue.front();
workQueue.pop_front();
for(SearchNode* passableNeighbor : getPassableChildren(sn)) {
// THIS IF-STATEMENT IS BROKEN
if(passableNeighbor->cell.first == maze->goal.first &&
passableNeighbor->cell.second == maze->goal.second) {
printf("Found a path.\n");
return;
}
// Check to make sure it is not in our visited set.
// THIS STATEMENT IS ALSO BROKEN
if (visited.find(passableNeighbor->cell) == visited.end()) {
workQueue.push_back(*passableNeighbor);
visited.insert(passableNeighbor->cell);
}
}
}
printf("No path found.\n");
}
// <...snip...>
The code compiles fine under GCC 4.6.3: $g++ maze.cc -g -std=c++0x
However, $./a.out smallMaze.txt produces
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
I've done some sanity checking with Valgrind and GDB:
Valgrind points out that Conditional jump or move depends on uninitialised value(s) in the line that begins
if(passableNeighbor->cell.first == maze->goal.first
and the line nearby that does a set lookup,
if(visited.find(passableNeighbor->cell) == visited.end())
When I inspect these passableNeighbor pointers in GDB, it does look like the underlying SearchNode object hasn't had it's child cell initialized properly, with all sorts of weird values cropping up. I suspect that this has to do with my lack of understanding of how C++ allocates objects.
So it's pretty clear that the underlying issue is that the passableNeighbor object somehow has corrupt data in it. Is this an artifact of how I wrote the getPassableChildren() method? Any other thoughts?
I've looked around at std::bad_alloc and it seems like this exception is usually related to running out of memory, but I'm getting this error on my very first node expanded during BFS, so it seems extremely unlikely that I'm hitting any memory limit.
This part has a problem
if(isPassable(mazePointer, childCell)) {
// Build child SN
SearchNode child;
child.cell = childCell;
child.parent = &sn;
child.pMaze = mazePointer;
sn.children.push_back(&child);
}
in that it fills the children with pointers to a local variable. When you leave the if-statement, all the pointers are invalid.
If you create a new child here, you have better store its value than store a pointer.
You are adding to the children vector the address of a local variable, a big no-no
SearchNode child;
child.cell = childCell;
child.parent = &sn;
child.pMaze = mazePointer;
sn.children.push_back(&child);
Use some sort of allocation, or make your children be a vector<SearchNode>
E.g:
SearchNode *child = new SearchNode();
child->cell = childCell;
child->parent = &sn;
child->pMaze = mazePointer;
sn.children.push_back(child);
Then you will need to clean this up later, or make your vector vector<unique_ptr<SearchNode>> and push on unique_ptr<SearchNode>(child) and the de-allocation will be done for you