STL List to hold structure pointers - c++

I have a structure called vertex and I created some pointers to them. What I want to do is add those pointers to a list. My code below, when it tries to insert the pointer into the list, creates a segmentation fault. Can someone please explain what is going on?
#include <iostream>
#include <list>
#define NUM_VERTICES 8
using namespace std;
enum { WHITE, GRAY, BLACK };
struct vertex
{
int color;
int distance;
char parent;
};
int main()
{
//create the vertices
vertex r = {WHITE, NULL, NULL};
//create pointer to the vertex structures
vertex *pr = &r;
//create a list to hold the vertices
list<vertex*> *r_list = new list<vertex*>;
list<vertex*>::iterator it;
r_list->insert(it, pr);
}

There are several things wrong here.
First off, you aren't initializing the iterator, like other's have said:
list<vertex*>::iterator it = r_list->begin();
Do this and your code will be fine. But your code is done in a bad manner.
Why are you allocating the list from the heap? Look at your code: you have a memory leak. You aren't calling delete r_list anywhere. This is why you should use smart pointers (std::unique_ptr, std::shared_ptr if you have C++11, boost equivalents otherwise : boost::scoped_ptr and boost::shared_ptr)
But better yet, just do it on the stack:
//create a list to hold the vertices
list<vertex*> r_list;
list<vertex*>::iterator it = r_list->begin();
r_list.insert(it, pr);
In addition, using the iterator to insert is going about things the long way. Just use push front() or push back():
//create a list to hold the vertices
list<vertex*> r_list;
r_list.push_back(pr);
Another thing: if your list outlives the vertex you've constructed, it will be pointing to something invalid.
For example:
// global
list<vertex*> r_list;
void some_function(void)
{
//create the vertices
vertex r = {WHITE, NULL, NULL};
//create pointer to the vertex structures
vertex *pr = &r;
r_list.push_back(pr);
} // right here, vertex r stops existing: the list now contains an
// invalid pointer.
One solution is to store pointers to heap-allocated vertices:
// global
list<vertex*> r_list;
void some_function(void)
{
//create the vertices
vertex *r = new vertex;
r->color = WHITE;
r->distance = 0;
r->parent = 0;
r_list.push_back(r);
}
Now even after the function the list is pointing to a valid heap-allocated vertex. This now has the problem that when you're done using the list, you need to go through the lsit and call delete on each element. This problem is assisted by using the Boost Pointer Container Library.
The best way, though, is to just store vertices themselves (rather than pointers to them):
//create a list to hold the vertices
list<vertex> r_list;
//create the vertices
vertex r = {WHITE, NULL, NULL};
r_list.push_back(r);
If you give vertex a constructor, you can even just construct them in-place:
struct vertex
{
int color;
int distance;
char parent;
vertex(int _color, int _distance, char _parent) :
color(_color),
distance(_distance),
parent(_parent)
{
}
};
//create a list to hold the vertices
list<vertex> r_list;
r_list.push_back(vertex(WHITE, NULL, NULL));
(these are now outside your problem)
Firstly, NULL is generally only used when dealing with pointers. Since distance and parent are not pointers, use 0 to initialize them, rather than NULL:
//create the vertices
vertex r = {WHITE, 0, 0};
Secondly, use constants rather than #define:
#define NUM_VERTICES 8 // <- bad
const int NumberVertices = 8; // <- good
Lastly, give your enum a name, or place it in a namespace:
enum Color { WHITE, GRAY, BLACK };
Hope these help!

You haven't initialised the iterator, so it's not valid to insert with. You could use r_list->push_back(pr) instead, for example.
Also, the pointers in your list aren't going to be valid once r goes out of scope. Obviously that's not a problem in this case since it's in main(), but I assume this isn't the exact example where you're going to use the code, so it may come back to bite you...

First of all, you aren't initializing it to anything. Do you mean:
list<vertex*>::iterator it = r_list->begin();
Also, why are you initializing an int and char to NULL? Usually people use NULL for pointers.
Also, how about naming your enum and benefiting from the type safety of enums, instead of using them as ints?
Also, no need to create a new variable to make a pointer to the vertex. When you call insert, you can pass in &r.
Also, as Peter points out, why not just use push_back()?
Your code should look more like this:
using namespace std;
enum Color {
WHITE,
GRAY,
BLACK
};
struct vertex
{
Color color;
int distance;
char parent;
};
int main(int argc, char** argv) {
//create the vertices
vertex r = {WHITE, 0, ''};
//create a list to hold the vertices
list* r_list = new list();
list::iterator it = r_list->begin();
r_list->insert(it, &r);
// Or even better, use push_back (or front)
r_list->push_back(&r);
}

You have not initialized it, so you're inserting at a random/uninitialized place/pointer.
Normal ways of adding items to a std::list include its methods push_back and push_front; you'd normally use insert only if you had previously otherwise determined the specific spot in which you want to insert one more item.

Related

C++ Error "left operand must be l-value"

I am trying to write a C++ program so solve Rubik's cubes. I have defined four classes: Piece, Edge, Corner, and Cube where Corner and Edge are subclasses of Piece.
The Cube class is defined as such:
class Cube{
private:
Piece* pieces[3][3][3];
public:
Corner* WRG = new Corner(WHITE, RED, GREEN, WHITE);
Corner* WGO = new Corner(WHITE, GREEN, ORANGE, WHITE);
Corner* WOB = new Corner(WHITE, ORANGE, BLUE, WHITE);
Corner* WBR = new Corner(WHITE, BLUE, RED, WHITE);
Corner* YRB = new Corner(YELLOW, RED, BLUE, YELLOW);
Corner* YBO = new Corner(YELLOW, BLUE, ORANGE, YELLOW);
Corner* YOG = new Corner(YELLOW, ORANGE, GREEN, YELLOW);
Corner* YGR = new Corner(YELLOW, GREEN, RED, YELLOW);
Edge* WR = new Edge(WHITE, RED, WHITE);
Edge* WB = new Edge(WHITE, BLUE, WHITE);
Edge* WO = new Edge(WHITE, ORANGE, WHITE);
Edge* WG = new Edge(WHITE, GREEN, WHITE);
Edge* YR = new Edge(YELLOW, RED, YELLOW);
Edge* YB = new Edge(YELLOW, BLUE, YELLOW);
Edge* YO = new Edge(YELLOW, ORANGE, YELLOW);
Edge* YG = new Edge(YELLOW, GREEN, YELLOW);
Edge* GO = new Edge(GREEN, ORANGE, GREEN);
Edge* GR = new Edge(GREEN, RED, GREEN);
Edge* BO = new Edge(BLUE, ORANGE, BLUE);
Edge* BR = new Edge(BLUE, RED, BLUE);
Cube();
~Cube();
void rotateRedClock();
void rotateRedCounter();
void rotateOrangeClock();
void rotateOrangeCounter();
void rotateYellowClock();
void rotateYellowCounter();
void rotateGreenClock();
void rotateGreenCounter();
void rotateBlueClock();
void rotateBlueCounter();
void rotateWhiteClock();
void rotateWhiteCounter();
void doMove(int);
Piece getPieces();
Cube* getChildren();
};
Cube::Cube(){
Piece* pieces[3][3][3] = { { { WRG, WR, WBR }, { GR, NULL, BR }, { YGR, YR, YRB } }, //Red face
{ { WG, NULL, WB }, { NULL, NULL, NULL }, { YG, NULL, YB } }, //Middle section
{ { WGO, WO, WOB }, { GO, NULL, BO }, { YOG, YO, YBO } } }; //Orange face
}
This array is stored inside of a Cube object that can shuffle the pointers in the array and change an orientation parameter for each Piece to handle rotations. From what I can tell, this all should work fine.
The problem starts when I try to return an array of Cube objects that contains all the moves possible from the current state.
If I were programming this in Java, it would look like this:
public Cube[] getChildren(){
Cube children = new Cube[12];
for (int i = 0; i < 12; i++){
children[i] = new Cube(this.getPieces()); //Effectively clone this
children[i].doMove(i); //Does one of the 12 available moves on the cube
}
return children;
}
In C++, however, I can't seem to accomplish this goal. I tried the following:
Cube* Cube::getChildren(){
Cube* children = new Cube[12];
for (int i = 0; i < 12; i++){
children[i] = Cube();
children[i].pieces = pieces;
children[i].doMove(i);
}
return children;
}
But I get an error on this line:
children[i].pieces = pieces;
It says:
error C2106: '=' : left operand must be l-value
I am new to C++, and this error is probably a result of my lack of understanding of certain concepts. I would like to know what I am doing wrong so I can avoid this sort of problem in the future. Thanks in advance!
Don't use raw pointers and don't use new anywhere in your code. The C++ equivalent of Java's Cube[] is std::vector<Cube>. Your sample function could look like:
std::vector<Cube> Cube::getChildren() const
{
// 12 copies of current state
std::vector<Cube> children(12, *this);
for (int i = 0; i < children.size(); i++)
{
children[i].doMove(i);
}
return children;
}
There are other changes to be made before this will work though (as things stand, a huge amount of memory will be leaked, and the "copies" will affect each other).
I'm guessing that the last argument to your Corner and Edge constructor is meant to be some sort of orientation indicator, which you will change when the pieces are rotating. So the variables WRG, WGO are supposed to be mutable and encode the current orientation of that piece.
In C++, objects should have value semantics. In this case, it means that copying the object should do a "deep copy", aka. a clone. There should not ever be code for implementing the copy except for inside the object's constructor.
So the issue of attempting children[i].pieces = pieces inside the getChildren function would never even come up if your objects are designed to use value semantics.
If your object design includes 27 pointers to mutable members of the class, then the default-generated copy constructor will do the wrong thing because:
all "copies" actually have the same pointer to pieces -- there's only one actual set of pieces. (Reorienting the piece in a new cube will reorient the piece in the cube it was copied from)
Even if that is fixed, the "copy" will point to pieces of the original cube, instead of pieces of the copied cube.
So, this is not a good design in C++.
It would be better to just hold the pieces by value. An improvement on your original code (but still not workable yet) would be:
Corner WRG {WHITE, RED, GREEN, WHITE};
Edge WR {WHITE, RED, WHITE};
Pieces *pieces[3][3][3] =
{ {&WRG, &WR, &WBR}, {&GR, nullptr, &BR}, // etc...
With this version, at least there is no memory leak, however there is still the problem that the default-generated copy constructor will have the new cube's Piece pointers copying at the old cube's Pieces.
There are three ways to fix this:
Write a copy-constructor (and a copy-assignment operator) which detects which piece the old cube's pointers point to and make each corresponding pointer in the new cube point to the new piece
Make the pieces be static so there really is only one set of pieces. The orientation will be remembered using separate variables.
Hold the pieces by value instead of by pointer.
1 is what you are trying to do at the moment and actually harder than it looks; even if you fix the compilation error by using std::copy or equivalent, you still have the pointers pointing to the old cube's pieces.
2 is a good idea. If there is only one set of pieces then you can copy around pointers to pieces without causing any trouble. Of course, then you need each Cube to have a new array to represent the current orientation of each piece . That's still simpler than #1 though!
This option also has the big bonus of decimating the memory footprint of each state.
(see below for more comments on #3 and memory usage).
Here is how an implementation of strategy 2 might look like. In the definitions of Edge and Corner take out the field corresponding to the orientation.
class Cube
{
// "static" means only one copy of each for the whole program
// The constructor arguments for each one are placed in the .cpp file
static constexpr Corner WRG, WGO, WOB, /*....*/ ;
static constexpr Edge WR, GR, /*.....*/ ;
Pieces const *pieces[3][3][3] =
{ {&WRG, &WR, &WBR}, {&GR, nullptr, &BR}, // etc...
typedef unsigned char Orientation;
Orientation orientation[3][3][3] = { };
public:
// no default constructor needed if you got the above lists right
// no destructor needed either way
// Cube();
void rotateRedClock();
void rotateRedCounter();
// etc. - you'll probably find it easier to roll all of these into
// a single function that takes the face and the direction as parameter
void doMove(int); // suggest using an enum to describe possible moves
// not necessary getPieces();
vector<Cube> getChildren() const;
};
If you are planning some sort of solving algorithm, you'll want to reduce the memory footprint of each state. So 3 is also a good idea.
If you adopt #2, then doing #3 is not quite so pressing - you can make your code work via approach #2 and optimize it later.
To use #3, you will need to discard the idea of using Piece * polymorphically.
However you don't need this feature anyway because you can tell from the array indices whether the piece is supposed to be a Corner or an Edge. I would suggest just using Piece to be basically what Corner is now but without the orientation; and ignore the third field when you're expecting an edge.
My suggestion would be to replace the table of 27 pointers with a table of 27 bytes . Then, in your .cpp file you'd have a lookup table that you can use to get the piece corresponding to that index.
Check the edit history for my post to see a rough outline of how that might look. (I initially wrote that, but then decided that the current version would be a bit easier to digest!)
In C++, you cannot assign another array to an array of fixed length. You have to copy the values individually. (Not 100% sure, but pretty sure.)
In the definition of class Cube, did you mean a pointer to such an array, i.e. did you mean
typedef Piece PieceArray [3][3][3];
PieceArray * pieces;
In your code, you do not declare a pointer to an array of pieces, but an array of pointers to pieces.
Do yourself a favour and use std::vector.
You didn't provide how Cube::pieces look like pieces and have type int[3][3][3]. The problem that it is C-style array and C very weakly typed, so neither C nor C++ cannot distinguish int[3][3][3] from int[2][2] - type information is lost.
Consider using C++ array types - they define copy constructors and assignment operators and save their sizes internally, so they will do all work for you. Lets take a ride!
C style array
As we already know, this will not work, this is just an example.
int main() {
int i[2][2] = { {0, -1}, {1, 2} };
int b[2][2];
b = i; /* cube.cpp:5:9: error: invalid array assignment */
}
std::vector
For that you will need to define vector of vectors of vectors:
#include <vector>
int main() {
std::vector<std::vector<int> > i = { {0, -1}, {1, 2} };
std::vector<std::vector<int> > b;
b = i;
}
boost::multi_array
(This will require external library)
#include <boost/multi_array.hpp>
int main() {
boost::multi_array<int, 2> i(boost::extents[2][2]);
/* Note that for multi_array we need single-dimentional initializer */
auto _i = { /*{*/ 0, -1 /*}*/,
/*{*/ 1, 2 /*}*/ };
i.assign(_i.begin(), _i.end());
boost::multi_array<int, 2> b(boost::extents[2][2]);
b = i;
}
This may seem more complex than other solutions, but multi_array may be a bit more efficient than vector of vectors.

Adding of a vertex in graph using adjacency-list in c++

This is how I've defined my graph. This is not a typical graph, it is specific to the type of problem I'm dealing with.
class Vertex;
class Edge
{
public:
Vertex *org;
Vertex *dest;
bool dir;
};
struct Vertex{
int id;
vector<Edge> edges;
int weight;
};
struct Graph{
vector<Vertex> vertices;
};
I'm having problem in adding a vertex in the graph. This is how I'm doing it
Graph* graph1;
Vertex* first = addVertex(0);
graph1->vertices.push_back(*first);
The addVertex function is working properly, but if you still want to refer, here it is
Vertex* addVertex(int id){
Vertex*newVertex = new Vertex;
newVertex->id=id;
newVertex->weight=0;
return newVertex;
}
The function stops working just before graph1->vertices.push_back(*first);
graph1 itself is an unitialized pointer. So, calling it's members is causing the program to crash. Initialize it with new operator.
graph1 = new Graph();
// .......
delete graph1;
Or use a smart pointer like std::unique_ptr to automatically manage memory.
In addition to the uninitialized Graph* graph1, there is another memory management problem in your code:
addVertex allocates a single Vertex in its own block of heap memory. But then
graph1->vertices.push_back(*first);
copies first into the block of memory managed by graph1's std::vector.
I guess that you are new to C++ coming from another language like Java or Python. You should read an introductory C++ book. Memory management in C++ has a lot of pitfalls and concepts to keep track of compared to other languages.

Trouble with List or Pointers, Adjacency Representaiton of Graph

The following code is the the beginning of an adjacency list representation of a graph.
In the buildGraph, which is immediately called by main, two vertices are created, then an edge is created between them. But then asking for the size of the edgelist of a vertex should return 1, not 0. I have tried putting couts in various places, and I'm just not able to figure out what the problem is, but I suspect it's due to a misunderstanding of pointers in some way. Thank you for your help!
#include "MinCut.h"
#include <iostream>
#include <list>
void buildGraph(undirected_graph *);
class vertex;
struct edge
{
vertex * start;
vertex * end;
};
class vertex
{
int vertexNumber;
std::list<edge> edges;
public:
int getVertexNumber(){return vertexNumber;}
std::list<edge> getEdges(){return edges;}
vertex(int n){vertexNumber=n;}
};
class undirected_graph
{
private:
std::list<vertex> graph;
public:
void addVertex(vertex v){graph.push_back(v);}
void createEdge(vertex * v1, vertex * v2);
};
void undirected_graph::createEdge(vertex * v1, vertex * v2)
{
std::list<edge> e1 = v1->getEdges();
std::list<edge> e2 = v2->getEdges();
edge e;
e.start=v1;
e.end=v2;
e1.push_back(e);
e2.push_back(e);
}
int main()
{
undirected_graph myGraph;
buildGraph(&myGraph);
return 0;
}
void buildGraph(undirected_graph * g)
{
vertex v1(1);
vertex v2(2);
g->addVertex(v1);
g->addVertex(v2);
g->createEdge(&v1,&v2);
std::list<edge> e = v1.getEdges();
std::cout<< "? " << e.size();
}
In createEdge() you have this:
e.start=v1;
e.start=v2;
Should it instead be
e.start=v1;
e.end=v2;
EDIT: Your problem is in createEdge, e1 and e2 are just copies, so changes don't affect the actual vertex objects.
Here's my solution, seems to be working:
Add a function to vertex like so:
void addEdge(edge &e){edges.push_back(e);}
Then in createEdge():
edge e;
e.start=v1;
e.end=v2;
v1->addEdge(e);
v2->addEdge(e);
In addition to #PatLillis's answer, I think you're also going to run into problems here:
vertex v1(1);
vertex v2(2);
g->addVertex(v1);
g->addVertex(v2);
g->createEdge(&v1,&v2);
The pointers &v1 and &v2 refer to v1 and v2 in your main function. However:
Since you're passing v1 and v2 by value to addVertex, you're going to get copies of those vertices in addVertex. That means your pointers in main will be pointing one place, and the copies will be somewhere else.
Since you're storing your vertices by value in a std::list, you'll have the same problem again. The list will hold copies of the copies in addVertex, and your pointers will still be pointing to the originals in main.
One way to fix this is to deal with vertex* in e.g. addVertex and in your std::list. Alternatively, if you want your graph to "own" the vertices (as opposed to them having potentially separate lifetimes from the graph) you could switch to std::unique_ptr<vertex>.

Pushing pointers into c++ vectors, and cleanup

I am converting some code between different systems, and I have a question regarding c++ vectors.
If I do something like this:
In header file:
struct Vertex
{
float x;
float y;
float z;
}
struct submesh
{
Vertex *meshdata;
}
std::vector<submesh> meshes;
In a routine in the c++ file:
{
Vertex *data = new Vertex[1024];
submesh g;
g.meshdata = data;
meshes.push_back(g);
delete [] data;
}
Will I be in trouble? My assumption is that the vector would hold a pointer to data that is no longer valid once I called delete on it. Do I need to write a copy constructor for Vertex so that the data is copied first?
Additional:
The question was more to do with how do I put a pointer to allocated memory into a std::vector<> and still cleanup the locally allocated data. Essentially, how do I copy the data into the vector so I can still clean up my copy.
The original code was in DirectX. I am porting it to the iPhone. The original code allocated a submesh locally in a routine using:
{
ID3DXMesh* subMesh = 0;
D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh));
//
// ... do some magical things to submesh
//
SubGrid g;
g.mesh = subMesh;
g.box = bndBox;
mSubGrids.push_back(g);
}
I am trying to duplicate how ID3DXMesh is able to be added to a vector, then lose it's scope in the routine.
As I don't have access to D3DXCreateMesh(), I figured I would simply allocate the vertices I needed, throw them into a vector, and clean up.
Sorry, I wanted to keep the nitty gritty details out of it, as the question is simply how do I allocate a chunk of data, put a pointer into a std::vector<>, then clean up the locally allocated memory. :)
I assumed a copy constructor had to be written somewhere. Just wasn't sure where or how.
A subgrid looks like this:
struct SubGrid
{
ID3DXMesh* mesh;
AABB box;
// For sorting.
bool operator<(const SubGrid& rhs)const;
const static int NUM_ROWS = 33;
const static int NUM_COLS = 33;
const static int NUM_TRIS = (NUM_ROWS-1)*(NUM_COLS-1)*2;
const static int NUM_VERTS = NUM_ROWS*NUM_COLS;
};
And the vector they get added to looks like:
std::vector<SubGrid> mSubGrids;
Don't directly dynamicly-allocate when you don't need to, and in this case you don't. Since you're filling your own submesh data rather than using ID3DXMesh, the container of that data should be RAII-compliant. If I were coding this I would remove the submesh class entirely and just use:
// vector containing list of vertices.
typedef std::vector<Vertex> SubMesh;
Your SubGrid class can then become a simple container that holds, as one of its properties, a submesh collection. I noticed you also have a class AABB for a box object. You would continue to keep that inside SubGrid. I don't have ton to work with here, so I'm making some of these up as I go along, but something like the following:
// a simple 3-value triplet of floats
struct Vertex
{
float x,y,z;
};
// a Submesh is an arbitrary collection of Vertex objects.
typedef std::vector<Vertex> SubMesh;
// I'm defining AABB to be an 8-vertex object. your definition
// is likely different, but I needed something to compile with =)
typedef Vertex AABB[8];
class SubGrid
{
public:
SubGrid() {};
// comparator for container ordering
bool operator <(const SubGrid&);
// submesh accessors
void setSubmesh(const SubMesh& mesh) { submesh = mesh;}
SubMesh& getSubmesh() { return submesh; }
const SubMesh& getSubmesh() const { return submesh; }
// box accessors
AABB& getBox() { return box; }
const AABB& getBox() const { return box;}
private:
SubMesh submesh;
AABB box;
};
// arbitrary collection of SubGrid objects
typedef std::vector<SubGrid> SubGrids;
When adding this to your global SubGrid collection g, you have several possibilities. You could just do this:
// declared globally
Subgrids g;
// in some function for adding a subgrid item
SubGrid subgrid;
AABB& box = subgrid.getBox();
SubBesh& submesh = subgrid.getSubmesh();
// ... initialize your box and submesh data ...
g.push_back(subgrid);
But you'd be copying a lot of data around. To tighten up the memory access you could always do this instead:
// push an empty SubGrid first, then set it up in-place
g.push_back(SubGrid());
Subgrid& subgrid = *(g.back());
AABB& box = subgrid.getBox();
SubMesh& submesh = subgrid.getSubmesh();
//... initialize your box and submesh data ...
This will establish a reference to the SubGrid just added to the global collection, then allow you to modify it in-place. This is but-one of a number of possible setup options. It should be noted that if you have C++11 in your toolchain (and if you're doing this on MacOS or iOS, you likely do, as Apple LLVM 4.2's clang is pretty good on C++11 compliance) this can get even more efficient with judicious usage of move-constructors and move-assignment-operators.
Most importantly, not a new or delete to be seen.
Anyway, I hope this gives you some ideas.
Your code looks fine in single threaded application. Your code only allocate data memory once and delete [] data once.
Do I need to write a copy constructor for Vertex so that the data is copied first?
Your code is clean as you shown, meshes points to only allocated data. If you meant to copy data when call meshes.push_back(g), then your code doesn't do what you meant to.
You might want to use std::vector instead:
struct submesh
{
std::vector<Vertex> meshdata;
}
vector<submesh> meshes;
void Func()
{
meshes.emplace_back(submesh());
meshes.at(0).meshdata.resize(100);
}
STL container uses RAII idiom, it manages memory deallocation for you automatically.
Yes of course, vector will have a pointer to deleted memory. What you need is either:
Create copy constructor for submesh (not Vertex).OR
Changesubmesh to have array of Vertex (not just a pointer).
Copy constructor can be done like this:
struct submesh
{
Vertex *meshdata;
unsigned meshsize;
submesh(Vertex* v = 0, unsigned s= 0) : meshdata(v), meshsize(s){}
submesh(const submesh& s)
{
if(meshdata) /*we have stored data, delete it.*/ delete(meshdata);
meshdata = new Vertex[s.meshsize];
meshsize = s.meshsize;
memcpy(meshdata, s.meshdata, sizeof(Vertex) * meshsize);
}
};
For sure it is much recommended to use unique_ptr (if you use c++11) or auto_ptr for old c++. To avoid the nightmare of memory management as much as you can.
Check How to avoid memory leaks when using a vector of pointers to dynamically allocated objects in C++?

C++ adjacency list of pointers and structs

Working on adjacency list --> directed weighted graph
One class looks like this, i.e. header:
class CGraph;
class CMap {
public:
//voided constructors and destructors
//functions one is:
void SetDirGraph(string commands);
private:
CGraph* m_myMap;
};
Second class:
class CNode {
public:
//voided constructor and desctructor
int m_distance, m_vert;
bool m_isKnown;
};
typedef struct edges {
int v2, weight;
} edge;
class CGraph {
public:
CGraph(int map_size);
~CGraph(void);
void AddMap(int v1, int v2, int weight);
void AddEndVert(int v2, int weight);
private:
list<edge> List;
int size;
public:
CNode* verts;
};
I'm reading vertices from a file, and that works. My problem is I am having trouble creating an adjacency list based on the code given. I'm trying to use pointers first that points to a list and it is not working correctly. I don't know how to create my pointers to the list without writing over them.
void CMap::SetDirGraph(string command) {
istringstream buffer(command)
char ch;
int num, vert1, vert2, weight; //specify vertices and weight and number of vertices
buffer>>ch; //throw away first character (not needed)
buffer>>num // size of vertices
while(!buffer.eof()) { // keep reading until end of line
buffer>>v1; // vertex start
buffer>>v2; // vertex end
buffer>>weight;
m_myMap = new CGraph(map_size); //initialize m_myMap.
m_myMap->verts->m_vert = v1; // mymap->verts->vert points to first edge
m_myMap->AddMap(v1, v2, weight); // create list?
m_myMap->AddEndVert(v2, weight); //create list? push v2 and weight on my list using my list.
}
}
I've tried several different ways and I keep confusing myself, any point in the right direction would be awesome.
EDIT:
I have more code too if needed to be produced, just publishing the main stuff.
What I mean by "not working" is that I am just writing over the previous vertex. I don't know if I should create an array using m_myMap (tried and still writes over and get a memory error as well). No compiler errors.
I don't know how to create my pointers to the list without writing over them.
Apart from your application, the answer to this question is the new operator, which I assume you are aware of, since you used it within your example code. Code like int * a = new int(42); allocates memory for an int on the heap and you are responsible for cleaning it up when it is not needed anymore. You thereby have full control over how long a variable will be available. In int x = 42; int * a = &x; on the other hand, x will automatically be cleaned up when it runs out of scope, and a will be a pointer to a memory block that has no meaningful data in it anymore. If you try to dereference it, you will encounter undefined behavior, and, if you are lucky, your program will blow up.
If you can use the C++11 standard, or a library that offers smart pointers, you should prefer those over managing the pointer yourself whenever possible. A smart pointer is an object that holds the allocated memory and frees it automatically when it is destructed. More specific information depends heavily on which sort of smart pointer you are using. The reason for using smart pointers is that doing the management yourself is tedious and error prone. If you do not delete your pointers you had allocated, your application will keep on allocating more memory until it blows up some day (depending on how often and how much memory you allocate); this is called leaking. If you call delete more than once, your program will bail out as well. Here is an example of C++11 shared_ptr in your application:
class CMap
{
private:
std::shared_ptr<CGraph> m_myMap;
// etc.
};
// in SetDirGraph
m_myMap.reset( // if the smart pointer has previously been managing
// memory, it will free it before allocating new
new CGraph(map_size) // allocate CGraph as before
);
Besides that, what hopefully answers your question, I have run into several potential problems concerning your code:
Definitely wrong:
In SetDirGraph you set m_myMap->verts->m_vert = v1. m_myMap->verts is a pointer. You have freshly created m_myMap and thus verts is not initialized, hence pointing at a random block of memory. You then try to dereference it by m_myMap->verts->m_vert = v1. This cannot work. You need to create verts first, i.e. verts = new CNode;.
typedef struct edges { /* etc */ } edge; is a C construct and there is no need for the typedef wrapper in C++. It does work and all, but it is really redundant and lots of those constructs just pollute the namespace you are working in.
Do you really need pointers in the first place? Your provided snippets do not hint at why you would need to use them. You will want to reduce usage of pointers to a minimum (or at least use smart pointers, see above)