Alvin P. Schmitt
Alvin P. Schmitt

Reputation: 9

Instantiating a 2d array and using it in C++

I know C pretty well (10 years) but am a C++ newbie. I am getting the following eror:

hw2.cpp: In function ‘int main()’:
hw2.cpp:337:7: error: no match for ‘operator=’ (operand types are     ‘Graph’ and ‘Graph*’)
grph = new Graph(size);
   ^
hw2.cpp:337:7: note: candidate is:
hw2.cpp:17:7: note: Graph& Graph::operator=(const Graph&)
class Graph {
   ^
hw2.cpp:17:7: note:   no known conversion for argument 1 from ‘Graph*’   to ‘const Graph&’

My class and constructor is :

class Graph {
//
//  Class Graph --  contains the graph x, y of size Size showing          connectivity
 //                 (whether node X is connected to node Y) and the cost of
 //                 the connection between X and Y.
//
private:
int nNodes;
vector<vector<int>> gph;
public:
//
//  Constructors
//

explicit Graph(int size=50):nNodes(size){

    gph = new int *[size];
    for (int i = 0; i < size;i++)
        gph[i] = new int[size];
}
//
//  Destructors
//
~Graph(void){
    retgph();
}
//
//  Methods
//
void retgph(){

 }
 int getLength(
    int x,      // Node x
    int y){     // Node y
    return (gph[x][y]);
}
void setGraph(
    int nodeX,  // Node X
    int nodeY,  // Node Y
    int value   // Value to set it to.
    ){
gph[nodeX][nodeY]=value;
gph[nodeY][nodeX]=value;
return;
}

};

And my code in main is:

int main(){
Graph abc;  // graph object.
Open  opn;  // open set object.
int final;  // final node which should be destination.
const int size = 10;
const int source=0; // source node.
const int dest=5;   // destination node.
abc = new Graph(size);
opn  = new Open(size);

Please bear with me as I don't know what I am doing. I think ABC =NEW GRAPH(50) should instantiate an object ABC but the graph is built in the constructor Graph(int= size) and is GPH. What graph am I accessing when I say ABC.setNodeValue(1,2,3); ? The graph GPH in the class or another ABC instantiated? If it is the one instantiated (ABC) why does GPH appear in the class Graph at all? My thinking is that ABC is the one that will be manipulated by the methods (ABC.getNodeValue(47);) . Does GPH in the class just appear there as a model for the instantiation process? Also GPH is actually INT **GPH; . Any help you can give me would be greatly appreciated.

Upvotes: 0

Views: 214

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595782

Inside your Graph class, the gph member is a std::vector containing std::vector elements. std::vector is a wrapper for new[] and delete[], so there is no need to use them directly to allocate the vectors. To change a std::vector's size at runtime, you can use its resize() method instead, eg:

class Graph {
private:
    vector< vector<int> > gph;
public:
    explicit Graph(int size=50) {
        gph.resize(size);
        for (int i = 0; i < size; ++i)
            gph[i].resize(size);
    }

    /* You can even reduce the constructor even more,
    using the constructor initialization list, if you
    don't mind a little extra overhead temporarily...

    explicit Graph(int size=50)
        : gph(size, std::vector<int>(size) ) {
    }
    */

    /* not necessary to clear the vector during destruction,
    it is handled automatic by the vector's own destructor...

    ~Graph() {
        retgph();
    }
    */

    void retgph() {
        gph.clear();
    }

    int getLength(int x, int y) {
        return gph[x][y];
    }

    void setGraph(int x, int y, int value) {
        gph[x][y] = value;
    }
};

As for the rest off your code...

The new operator returns a pointer to a newly instantiated object that is allocated on the heap. So new Graph allocates a Graph object, calls the Graph() constructor on it, and returns a Graph* pointer to that object.

Your compiler error is because your abc variable is declared as a Graph instantiated object on the stack instead of a Graph* pointer. So, when you call abc = ..., you are actually calling the Graph::operator=() copy assignment operator (which in this case is auto-generated by the compiler for you). That operator expects a const Graph& (reference to a constant Graph object) as input, not a Graph* (pointer to a Graph object), thus the "no known conversion from Graph* to const Graph&" compiler error.

Same thing for your opn variable, using the Open class.

Change the abc and opn variables into pointers, and change any . to -> when accessing methods of those objects. And don't forget to delete the objects when you are done using them:

int main() {
    const int size = 10;
    Graph *abc;  // pointer to graph object.
    Open  *opn;  // pointer to open set object.
    abc = new Graph(size);
    opn  = new Open(size);
    //...
    abc->setGraph(x, y, value);
    opn->doSomething(parameters);
    //...
    delete opn;
    delete abc;
}

Or, use a std::auto_ptr or std::unique_ptr to handle the delete for you:

#include <memory>

int main() {
    const int size = 10;
    std::uninque_ptr<Graph> abc( new Graph(size) );
    std::unique_ptr<Graph> opn( new Open(size) )
    //...
    abc->setGraph(x, y, value);
    opn->doSomething(parameters);
    //...
}

Or, just keep instantiating them on the stack, but get rid of new and delete, and let them destruct themselves when they go out of scope when main() exits:

int main() {
    const int size = 10;
    Graph abc(size);
    Open opn(size);
    //...
    abc.setGraph(x, y, value);
    opn.doSomething(parameters);
    //...
}

Now, to answer your questions:

I think ABC =NEW GRAPH(50) should instantiate an object ABC but the graph is built in the constructor Graph(int= size) and is GPH.

abc = new Graph(50) instantiates a new Graph object with a constructor value of 50, and then assigns that object pointer to abc. Internally, the Graph constructor instantiates the gph vectors using the specified size.

What graph am I accessing when I say ABC.setNodeValue(1,2,3); ? The graph GPH in the class or another ABC instantiated?

You are accessing the abc object, which internally accesses the gph vectors.

If it is the one instantiated (ABC) why does GPH appear in the class Graph at all?

It is a piece of data that is inside of the abc object. Think of Graph as an envelope, and gph as a thing inside of the envelope, and abc as the hand that is holding the envelope. Each time new Graph is called, a new envelope is created with a new gph inside of it.

My thinking is that ABC is the one that will be manipulated by the methods (ABC.getNodeValue(47);) .

Yes.

Does GPH in the class just appear there as a model for the instantiation process?

No. It is one of the things being instantiated.

Also GPH is actually INT **GPH;`

Not in the code you have shown. But logically, that is equivalent to how a 2-dimensional std::vector behaves at runtime - a pointer (inside the outer vector) to a dynamic array (what the outer vector manages) of pointers (the inner vectors) to dynamic arrays (what the inner vectors manage) of integers (what the inner vectors hold).

The C equivalent of the above code would look something like this:

struct Graph {
    int size;
    int **gph;
};

struct Open {
    //...
};

Graph* createGraph(int size=50) {
    Graph *g = (Graph*) malloc(sizeof(Graph));
    g->size = size;
    g->gph = (int**) malloc(sizeof(int**) * size);
    for (int i = 0; i < size; ++i)
        gph[i] = (int*) malloc(sizeof(int) * size);
    return g;
}

Open* createOpen(int size=50) {
    Open *o = (Open*) malloc(sizeof(Open));
    //...
    return o;
}

void retGraph(Graph *g) {
    for (int i = 0; i < g->size; ++i)
        free(gph[i]);
    free(g->gph);
    g->gph = NULL;
    g->size = 0;
}

void freeGraph(Graph* g) {
    retGraph(g);
    free(g);
}

void freeOpen(Open* o) {
    //...
    free(o);
}

int getLength(Graph *g, int x, int y) {
    return g->gph[x][y];
}

void setGraph(Graph *g, int x, int y, int value) {
    g->gph[x][y] = value;
}

void doSomething(Open *o, parameters) {
    //...
}

int main() {
    const int size = 10;
    Graph *abc = createGraph(size);
    Graph opn = createOpen(size)
    //...
    setGraph(abc, x, y, value);
    doSomething(opn, parameters);
    //...
    freeOpen(opn);
    freeGraph(abc);
}

Upvotes: 0

Lemon Drop
Lemon Drop

Reputation: 2133

When you initially say Graph abc; you are constructing a Graph object on the stack (using it's default constructor, which in this case is a defaulted conversion constructor giving the graph a size of 50).

You then try to assign something of type Graph * to this variable, as that is what new returns (a pointer to the newly constructed object on the heap), which clearly isn't the same type as what the variable is. This is why the compiler is complaining about the lack of an operator= (assignment operator) between those types, and is suggesting that you meant to use the copy assignment operator instead as it is a close match to what you're trying to do, but still not correct. Perhaps you are trying to do something such as:

const int size = 10;

Graph abc(size);
Open  opn(size);

Or perhaps if you do require that they are stored via pointer:

const int size = 10;

Graph *abc = new Graph(size);
Open  *opn = new Open(size);

// Do stuff...

delete opn;
delete abc;

Upvotes: 2

Related Questions