c++ 2d array of class pointers - c++

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;
}
}

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{} );
}
}

Assign address to pointer inside struct

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].

I need to update a Vector of pointers in C++ in a unique way

So I have a vector of pointers to a class I defined. I have a function that takes the 0 index of the pointer and returns it. After that I need to remove the data in that index then take the item in the last index of the vector and put it into the 0 index. As of right now I am just setting the pointers to NULL if I return them, and then I pushback the final object in the vector and finally pop it back. I am not sure if this method is the best way of solving my issue. Here is my code though:
Instrument* loanOut() {
for (int i = 0, i < library.size(), i++) {
if (library[i] != NULL) {
return library[i];
}
else {
return NULL;
}
}
library[0] = NULL;
library.push_back(library[library.size()]);
}
Algorithmically, this is what you are describing :
Object PopFrontAndReplace(std::vector<Object>& objects) {
if (!objects.size()) {return Object();}
Object o = objects[0];
objects[0] = objects.back();
objects.pop_back();
return o;
}
Does that answer the question?

I am stuck with copying a class given an address, I am segfaulting

I have struggled with it for a while but I really can't get it, I am just getting segfaults. I am trying to copy a class, the function I am writing to copy is also below. Crossed out are combinations that I have tried in vain, it's time to call for help
class Scene
{ private:
int max;
int* x_row, *y_col; // maximum and min coordinates of each image
Image**image_layers;
}
void Scene::_copy(const Scene &source)
{
max = source.max;
x_row = new int[source.x_row];
y_col = new int[source.y_col];
image_layers = new Image*[source.max];
for(int i = 0; i < source.max; i++)
{
if(source.image_layers[i] != NULL)
{
//image_layers[i] = new Image(*(source.image_layers[i]));
// image_layers[i] = new Image;
//*image_layers[i] = *source.image_layers[i];
// image_layers[i] = source.image_layers[i];
}
else
{
image_layers[i] = NULL;
}
x_row[i] = source.x_row[i];
y_col[i] = source.y_col[i];
}
EDIT:
I forgot to say that this function is called as " scene(*set) "
The segfault happens here or because of this:
x_row = new int[source.x_row];
y_col = new int[source.y_col];
On the right hand side, you use the address source.x_row as an array size. This is a very large number that most likely will cause the allocation to fail.
You need to keep a member for holding the size or better yet use a std::vector<int> object instead.
Copying C arrays are done faster with memcpy. With C++ vectors, you can just assign one to the other:
x_row = source.x_row
Nothing to do with the question, but this function should be named operator=, will make using the class easier by assigning one instance to another:
Scene & Scene::operator=(const Scene &source)
{
// copy elements
...
return *this;
}
x_row = new int[source.x_row];
y_col = new int[source.y_col];
Are you sure about above code?
source.x_row is pointer

c++ Dynamic 2d array not using default constructor

I got a problem that is beyond my knowledge. I'm working on a HGE project, but this is a c++ issue, not the HGE engine itself.
The question:
I want to create a 2D array with 3 different animations on 5 different turtles. However, I need to use a constructor in HGE something like this;
turtleAnim[i] = new hgeAnimation( turtleTexture, 6, 6, 0, 0, 110, 78 )
But I don't know how to do it! All examples on the interwebz handle the problem as if it got a default constructor. Something like this:
in class:
#define TURTLECOUNT 5
#define TURTLEANIMATIONS 3
private:
hgeAnimation** turtleAnim;
in the.cpp
turtleAnim= new hgeAnimation*[TURTLECOUNT];
for(int i=0; i<TURTLECOUNT; i++)
{
turtleAnim[i]= new hgeAnimation[TURTLEANIMATIONS]; // Uses default constructor. I don't want that cuz it doesn't exists.
turtleAnim[i]->Play();
}
First, you have to decide whether you want your objects on the stack or the heap. Since they're objects, you probably want them on the heap, which means your 2D array will have 3 stars, and you will access the animations like this:
hgAnimation* theSecondAnimOnTheFourthTurtle = turtleAnim[4][2];
theSecondAnimOnTheFourthTurtle->DoSomething();
If that's what you want, then first you make the matrix of pointers.
hgeAnimation*** turtleAnim = new hgeAnimation**[TURTLECOUNT];
Then you can loop through the turtles. For each turtle, you make an array of pointers to the animations. For each element of that array, you make the animation itself.
for (int turt=0; turt<TURTLECOUNT; ++turt) {
turtleAnim[turt] = new hgeAnimation*[TURTLEANIMATIONS];
for (int ani=0; ani<TURTLEANIMATIONS; ++ani) {
turtleAnim[turt][ani] = new hgeAnimation(parameter1, par2, par3);
}
}
If that looks tricky, deleting all the arrays will be a pain too:
for (int turt=0; turt<TURTLECOUNT; ++turt) {
for (int ani=0; ani<TURTLEANIMATIONS; ++ani) {
delete turtleAnim[turt][ani];
}
delete[] turtleAnim[turt];
}
delete[] turtleAnim;
The fact that this is tricky is a good sign that there's probably a more simple way to design it.
How about a turtle class that has a member like:
class ATurtle {
private:
std::vector<hgeAnimation*> myAnimations;
Then in your class's constructor, you can do whatever you want in order to make the animations.
ATurtle::ATurtle(par1, par2, par3) {
myAnimations.push_back( new hgeAnimation(par1, x, y) );
myAnimations.push_back( new hgeAnimation(par2, z, a) );
myAnimations.push_back( new hgeAnimation(par3, b, c) );
}
That way, you can make your turtles in a single array:
ATurtle* turtles[TURTLECOUNT];
for (int t=0; t<TURTLECOUNT; ++t) {
turtles[t] = new ATurtle(par1, par2);
}
And in your turtle class, you would access the animations like so:
(*(myAnimations.at(1)))->DoSomething();
or
std::vector<hgAnimation*>::iterator i, end=myAnimations.end();
for (i=myAnimations.begin(); i!=end; ++i) {
(*i)->DoSomething();
}
You will still have to call delete on each element of your vector in this case, though, since you called new for every element.
ATurtle::~ATurtle() {
std::vector<hgAnimation*>::iterator i, end=myAnimations.end();
for (i=myAnimations.begin(); i!=end; ++i) {
delete (*i);
}
}