0

Issue : program crashing

here is my matrice.h :

class matrice {

public:
    matrice(int nbColumnTMP, int nbLineTMP);

    std::vector<std::vector<int>> returnArray();

    virtual ~matrice();

    void addValue(int numColumn, int numLine, int value);
    void editValue(int numColumn, int numLine, int numValue, int newValue);

private:
    std::vector<std::vector<int>>* array;
    int nbColumn;
    int nbLine;

};

And the .cpp :

matrice::matrice(int nbColumnTMP, int nbLineTMP) {

    nbColumn = nbColumnTMP;
    nbLine = nbLineTMP;

    std::vector<int>* array2;

    for(int C = 0; C < nbColumn; C++)
    {
        array->push_back(*array2);//<- DONT WORK, CRASH

        for(int L = 0; L < nbLine; L++)
        {
            array[C][L].push_back(0); //Init matrix with 0 values
        }
    }
}

std::vector<std::vector<int>> matrice::returnArray()
{
    return *array;
}

matrice::~matrice()
{
    for(int C = 0; C < nbColumn; C++)
    {
        for(int L = 0; L < nbLine; L++)
        {
            for(int V = 0; V < int(array[C][L].size()); V++)
            {
                delete &array[C][L][V];
            }

            delete &array[C][L];
        }

        delete &array[C];
    }

    delete  &nbColumn;
    delete &nbLine;

    delete array;
}

void matrice::addValue(int numColumn, int numLine, int value)
{
    array[numColumn][numLine].push_back(value);
}

void matrice::editValue(int numColumn, int numLine, int numValue, int newValue)
{
    array[numColumn][numLine][numValue] = newValue;
}

After a few tests, i found out that this make my program crash:

array->push_back(*array2);

I'm new to this so i'm not sure i'm doing things well, and i have no clue why this is not working...

I'm using this class for my 2D isometric engine, i want to load some coordinates into them to easily get isometrics coordinates after.

Madz
  • 287
  • 3
  • 14
  • 2
    Maybe that's happening, because you failed to initialize `array2`, AND `array`, and, in the constructor, you are dereferencing pointers that point to nowhere (have garbage values)? – Algirdas Preidžius Nov 11 '15 at 21:00
  • garbage values ? Sorry i don't know what is "dereferencing pointers" – Madz Nov 11 '15 at 21:00
  • `array2` isn't pointing anywhere and you try to `push_back` what it's pointing to (which is garbage). EDIT: Same for `array` – Kevin Nov 11 '15 at 21:03
  • Garbage values = values that don't mean anything, but just happened to sit at the memory where the variable is located. Dereferencing pointers = taking the value that is sitting at the memory location pointed to, by a pointer. – Algirdas Preidžius Nov 11 '15 at 21:04
  • After doing `std::vector array2;` and `array->push_back(array2);` , it's still crashing – Madz Nov 11 '15 at 21:06
  • @JohnnyMopp Well, from what I understood it's more like "What are pointers, and what do I do with them?" kind of question, rather than 2D `std::vector` kind of question. – Algirdas Preidžius Nov 11 '15 at 21:06
  • @Madz That's because `array` has the same problem. And you are dereferencing it with `->` operator. `a->b` is equivalent to `(*a).b`. – Algirdas Preidžius Nov 11 '15 at 21:07
  • @Algirdas Preidžius Aaah, sorry i'm new to stackoverflow. But i followed a code sample and i don't know why it's not going well so i couldn't precisely put labels. Just saw your answer, i'm really sorry, i don't understand (*a).b .... omg am i dumb... – Madz Nov 11 '15 at 21:09
  • After trying to not deferencing it(array), `array[C][L].push_back(0); //Init matrix with 0 values` -> push_back couldn't be resolved – Madz Nov 11 '15 at 21:12
  • `*a` returns a what `a` is pointing to. Your program is crashing because `array` isn't pointing to valid memory. The solution is to make `array` the vector itself instead of a pointer to it. – Kevin Nov 11 '15 at 21:12
  • when `array` was a pointer, `array[C]` is a 1 dimensional vector. Now that `array` is the vector you only need to specify a single dimension to push back, i.e. `array[C].push_back(0);` – Kevin Nov 11 '15 at 21:13

2 Answers2

2

The reason for your issues is that you're using a pointer member, and attempting to write to uninitialized memory.

There is no need for this member to be a pointer:

   std::vector<std::vector<int>>* array;

Instead, make it an object and size it appropriately in the constructor and other functions that size the vector:

   std::vector<std::vector<int>> array;

and then:

matrice::matrice(int nbColumnTMP, int nbLineTMP) : 
             array(nbColumnTMP, std::vector<int>(nbLineTMP))
{}

Also, there is no need to be holding onto variables that denote the number of rows and columns. Use the appropriate vector::size() methods. There is no need for nbColumn and nbLine member variables.

Using extraneous variables can invariably lead to bugs down the road (due to not updating them properly), or other issue that keeps them out-of-sync with the actual size of the vector. For example, your function to add a value -- since you seem to be creating a ragged 2 dimensional vector, those member variables denoting the number of rows and columns become useless, and the only thing reliable is to use the std::vector<T>::size() function.

Also, once you do this, there is no need for a destructor in your matrix class. The vector will clean itself up automatically when the object goes out of scope.

In general, if you want a 2 dimensional or 3 dimensional vector, and you want to start out "easy", then just declare one. Don't go the pointer route. If you did that, then it just becomes a matter of fixing a few syntax errors (or getting used to the syntax), and that is the easy stuff. Going headlong into pointers and dynamically allocated memory will lead you into all sorts of issues that you need not have to get into.

Edit:

For a 3 dimensional vector,

std::vector<std::vector<std::vector<int>>>;

or better yet:

typedef std::vector<int> Int1D;
typedef std::vector<Int1D> Int2D;
typedef std::vector<Int2D> Int3D;
Int3D array;

and then:

matrice::matrice(int nPages, int nbColumnTMP, int nbLineTMP) : 
             array(nPages, Int2D(nbColumnTMP, Int1D(nbLineTMP)))
{}
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • Thanks for your answer :) . This one don't work : `array[numColumn][numLine].push_back(value);` i don't get why – Madz Nov 11 '15 at 21:24
  • `array` is a 2d vector, `array[a]` is a 1d vector, and `array[a][b]` is an element (`int` in your case). You can't call `push_back` on an `int`. So either add another dimension to `array` or don't call `push_back` – Kevin Nov 11 '15 at 21:27
  • That is because `array[x][y]` is a value. It isn't a vector. You're trying to call `push_back` on something that isn't a vector. – PaulMcKenzie Nov 11 '15 at 21:28
  • You'll need to use my 3D version, you cannot call push_back on an int – Niels van Eldik Nov 11 '15 at 21:28
  • Looks like we are giving the same comments in parallel. Madz, try compiling my version. Try fixing the obvious compiler errors and if you don't manage post the compiler error – Niels van Eldik Nov 11 '15 at 21:29
  • @NielsvanEldik I didn't success to compile it Ok i'll try to compile again and i'll post the errors – Madz Nov 11 '15 at 21:33
  • try again removing the : in the constructor in the cpp file. The compiler should complain about that one at least – Niels van Eldik Nov 11 '15 at 21:36
  • @NielsvanEldik don't know why, i copy pasted again your code and now it's working, really thanks a lot – Madz Nov 11 '15 at 21:39
  • @PaulMcKenzie I like your latest version with the typedefs, that's the way to go, also your constructor is very neat and compact. I'd opt for your solution. I'd just use replace the int with an unsigned int: matrice::matrice(unsigned int nPages, unsigned int nbColumnTMP, unsigned int nbLineTMP) : array(nPages, Int2D(nbColumnTMP, Int1D(nbLineTMP))) {}. The dimensions should always be > 0. – Niels van Eldik Nov 11 '15 at 21:41
  • @NielsvanEldik I tought it was ok so i put this post as answered, but unfortunately, the function addValue you did write make my program crash. I may did something wrong when i do this ? `matrice* test = new matrice(1, 1); test->addValue(0, 0, 1);` – Madz Nov 11 '15 at 23:07
  • @Madz Forget that `new` exists and just use objects instead of pointers. You don't even need `new` anyway: `matrice test(1,1); test.addValue(0,0,1);` – PaulMcKenzie Nov 11 '15 at 23:08
  • @PaulMcKenzie When i do this, my program still crash :/ After a few checks, it's the addValue which is still making it crash But thanks for this anyway, i don't know why i love so much pointers ha ha Wow a 2 years break is so hard – Madz Nov 11 '15 at 23:11
  • @Madz Are you creating a 2D or a 3D matrix? For a 3D matrix, it works fine here: http://ideone.com/wBIl5J – PaulMcKenzie Nov 11 '15 at 23:32
  • I need to load in it the raw coordinates and iso coordinates(each one: two values(x, y)). – Madz Nov 11 '15 at 23:59
  • I want this : [[x, y, z], [x, y, z]] – Madz Nov 12 '15 at 02:19
0

It looks like you are also new to c++.

As was mentioned in the comment, you first need to initialize the array. Even better would be not to use pointers at all.

in your .h

class matrice {

public:
    matrice(int nbColumnTMP, int nbLineTMP);

    const std::vector<std::vector<std::vector<int>>>& returnArray() const;


    void addValue(int numColumn, int numLine, int value);
    void editValue(int numColumn, int numLine, int numValue, int newValue);

private:
    std::vector<std::vector<std::vector<int>>> array;
};

and .cpp

matrice::matrice(int nbColumnTMP, int nbLineTMP)  {

    array.resize(nbColumnTMP);

    for(int C = 0; C < nbColumnTMP; C++)
    {
        array.push_back(std::vector<std::vector<int>>(nbLineTMP));
    }
}

const std::vector<std::vector<std::vector<int>>>& matrice::returnArray() const
{
    return array;
}

void matrice::addValue(int numColumn, int numLine, int value)
{
    array[numColumn][numLine].push_back(value);
}


void matrice::editValue(int numColumn, int numLine, int numValue, int newValue)
   {
     // you should also add boundary checks for numColumn and numLine
     std::vector<int>& element = array[numColumn][numLine];
     if( numValue >= 0 && numValue < element.size() ){
        element[numValue] = newValue;
     }
   }

There are many excellent matrix packages avaliable, don't implement your own unless they don't support your needs. I use Eigen in the past, it significantly reduced CPU load of our core matrix operations.

Niels van Eldik
  • 211
  • 2
  • 7
  • Try again, the code is now 3D and I removed a typo or two. I did not try compiling it, I'm leaving that up to you. The current code should avoid the crashes you had before and if you also add the boundary checks . Consider using unsigned int instead of int for the getter/setter methods this avoids the < 0 check. – Niels van Eldik Nov 11 '15 at 21:26