Private array of adjacent node addresses in C++ - c++

////EDIT #2: Deleted all the previous info and just post the working code now. Previous question became too lengthy:
#include <iostream>
#include <vector>
using namespace std;
template<class T>
class Node{
T data;
vector<Node<T>*> adjacent;
friend class Graph;
public:
int n;
Node(T initData) : data(initData), n(0){}
void addAdjacent(Node<T>& other){
adjacent.push_back(&other);
n++;
}
T getData(){
return data;
}
Node<T>* getEdge(int edgeNum){
return adjacent[edgeNum];
}
};
template<class T>
class GraphCl{
int n;
vector<Node<T>*> nodes;
T input;
public:
GraphCl(int size): n(size){
for (int i=0;i<n;i++){
cout << "Enter data for node " << i << ": ";
cin >> input;
nodes.push_back(new Node<T>(input)) ;
}
}
void addEdge(int baseNode, int edgeNode){
nodes[baseNode]->addAdjacent(*nodes[edgeNode]);
}
void printGraph(){
for (int i=0;i<n;i++){
Node<T> *base = nodes[i];
cout << "Data of node " << i <<": "<< base->getData() <<endl;
for (int j=0;j<base->n;j++){
cout << "Edge #"<< j+1 << " of node " << i << ": " << base->getEdge(j) <<endl;
}
}
}
};
int main(){
GraphCl<int> *myGraph = new GraphCl<int>(5);
myGraph->addEdge(0,1);
myGraph->addEdge(0,2);
myGraph->addEdge(0,3);
myGraph->addEdge(0,4);
myGraph->addEdge(3,1);
myGraph->addEdge(3,0);
myGraph->printGraph();
return 0;
}
Output:
Enter data for node 0: -34
Enter data for node 1: 12
Enter data for node 2: 56
Enter data for node 3: 3
Enter data for node 4: 23
Data of node 0: -34
Edge #1 of node 0: 0x7fbeebd00040
Edge #2 of node 0: 0x7fbeebd00080
Edge #3 of node 0: 0x7fbeebe00000
Edge #4 of node 0: 0x7fbeebd000d0
Data of node 1: 12
Data of node 2: 56
Data of node 3: 3
Edge #1 of node 3: 0x7fbeebd00040
Edge #2 of node 3: 0x7fbeebd00000
Data of node 4: 23
As you can see this simple implementation is working. I decided to just cut out all the complicated stuff and keep it simple with dynamically changing vectors. Obviously less efficient but I can work from here on. Since I am new with C++ the previous implementation just got my head spinning 360 degrees thinking about where all the pointers to pointers went, without even thinking about memory allocation. The above code basically is a directed graph that is very sensitive to input errors, so I got to work on it still.
Thanks for all the help!

Accessibility
Regarding the accessibility of the array to the Graph, the closest thing to the current implementation is to declare declare Graph as a friend of Node. Simply add:
friend Graph;
To the end of the Node class declaration.
That said, making a class as a friend is sometimes a sign that the API you defined isn't exactly right if classes need to know too much about each others' implementation details. You can alternatively provide an interface for Node such as:
void AddAdjacent(Node* other);
Managing Adjacent Nodes
If you want your adjacent pointer array to be growable, then you are basically re-creating std::vector, so I would suggest using std::vector<Node*>. Initializing a vector with the default (empty) constructor would take care of it, and a nodes[baseNode]->adjacent.push_back(...) would be all you need in addEdges.
If memory is not a consideration and you have a maximal number of nodes in the graph, you can instantiate a constant-sized array.
If you really don't want to use std::vector, but you actually want a growable array of pointers, then you'll have to manage your own malloc and free calls. I'll write something up to that effect, but my advice is to just go ahead with vector.
In case you are curious, the array approach would look something like:
template<class T>
class Node : public Graph{
Node **adjacent; //pointer to array of POINTERS TO adjacent Nodes
int n;
size_t capacity;
T data;
friend Graph;
public:
Node(T initData) : data(initData), capacity(8) {
n = 0;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
}
~Node() {
free(adjacent);
}
void Grow() {
size_t new_cap = base.capacity * 2;
Node<int> **copy = reinterpret_cast<Node<int>**>(malloc(new_cap * sizeof(Node**)));
memcpy(copy, base.adjacent, base.capacity); // copy and adjacent are non-overlapping, we can use memcpy
free(base.adjacent);
base.adjacent = copy;
base.capacity = new_cap;
}
};
And the insertion:
Node<T>& base = nodes[baseNode];
Node<T>* edge = &(nodes[edgeNode]);
if (base.capacity == base.n) base.Grow();
base.adjacent[base.n++] = edge;

Answering the updated question
There are a few issues with putting Nodes directly in a std::vector in your case.
Using a std::vector is great for many things, but if you are doing that, you should make sure not to take pointers to vectors. Remember, pointers refer to exact addresses in memory of where an object is stored. A vector is a growable container of elements. To store elements contiguously, the vector allocates a bunch of memory, puts objects there, and if it has to grow, it will allocate more memory and move the objects around. It is essentially doing something similar to what you are doing in your Node and grow (except, in its case, its explicitly destroying the objects before freeing the old memory).
Notice that your Grow function allocates new memory and copies the pointers. Simlarly, vectors can allocate new memory and copy the data over. This means that holding pointers to data in a vector is bad. The only guarantee a vector gives you is that its data will continue to be accessible using array-style indexing, find, iteration, etc., not that the data will exist in the same memory location forever.
Explaining the exact bug you are seeing
The vector is invoking a copy constructor. The default copy constructor copies every field one-by-one. This is not what you want in the case of Node, because then you have two vectors that think they own the Node** adjacent memory location. When the first node (the old copy) is being destroyed, it will free its adjacent nodes (which is the same as the copy's adjacent node). When the new copy is being destroyed, it will attempt to free that same memory location, but it is already freed. You also have the problem here that, if you attempted to access the memory after it has been destroyed in the first node, you'll be in trouble.
Why was this bug showing up when you were only adding nodes?
When a vector grows to a certain amount, it needs to resize. In most implementation, the process is roughly:
Allocate a bunch more memory (usually twice the old capacity)
Invoke the copy constructor to copy elements from the old location to the new location
Destroy the elements in the old location (say, by explicitly calling the destructor)
Insert the new element in the new location
Your bug is showing up because of steps 2 and 3, basically.
Fixing this particular bug
For your case, the default copy constructor is no good because copying a node should meet a deep copy of all of the data. A regular copy in C++ will copy all of the data on the class or struct itself. If the data is a pointer, then the pointer is copied, not the thing its pointing to.
Override the copy constructor and assignment operator:
Node(const Node<T>& other) : data(other.data), capacity(other.capacity), n(other.n) {
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
Node<T>& operator= (const Node<T>& other) {
data = other.data;
capacity = other.capacity;
n = other.n;
adjacent = reinterpret_cast<Node**>(malloc(capacity * sizeof(Node**)));
memcpy(adjacent, other.adjacent, capacity * sizeof(Node**));
}
A Bigger Problem
A bigger problem with your code is that the use of an std::vector and pointers to its elements. Choose one of:
Use a fixed-sized array (which is stable in memory), and point to these objects
Forget about pointers altogether, and make your adjacent list a list of indices into the vector (its less performant as you need to go through the vector each time, but that likely won't be your bottleneck for now)

Related

How can I correctly push back a series of objects in a vector in C++?

The scope of the program is to create a Container object which stores in a vector Class objects. Then I want to print, starting from a precise Class object of the vector all its predecessors.
class Class{
public:
Class(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
}
}
};
~Class();
void setName(const int& n);
void setNext( vector<Class>& vec, const int& pos);
Class* getNext();
string getName();
void printAllNext(){ //print all next Class objects including himself
cout << _name <<endl;
if (_next != nullptr) {
(*_next).printAllNext();
}
}
private:
Class* _next;
string _name;
};
class Container{
public:
Container(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
};
~Container();
void printFromVec(const int& n){//print all objects of _vec starting from n;
_vec[n].printAllNext();
};
private:
vector<Class> _vec;
};
int main() {
Container c;
c.printFromVec(5);
}
The problem is that all _next pointers of Class objects are undefined or random.
I think the problem is with this part of code:
class Container{
public:
Container(){
for (int i = 0; i < 10; ++i) {
Class c;
c.setName(i);
if (i > 0) {
c.setNext(_vec,i-1);
}
_vec.push_back(c);
};
Debugging I noticed that pointers of already created objects change their values.
What is the problem? How can I make it work?
Although there is really error in the code (likely wrong copypaste), the problem is really following: std::vector maintains inside dynamically allocated array of objects. It starts with certain initial size. When you push to vector, it fills entries of array. When all entries are filled but you attempt pushing more elements, vector allocates bigger chunk of memory and moves or copies (whichever you element data type supports) objects to a new memory location. That's why address of object changes.
Now some words on what to do.
Solution 1. Use std::list instead of std::vector. std::list is double linked list, and element, once added to list, will be part of list item and will not change its address, there is no reallocation.
Solution 2. Use vector of shared pointers. In this case you will need to allocate each object dynamically and put address into shared pointer object, you can do both at once by using function std::make_shared(). Then you push shared pointer to vector, and store std::weak_ptr as pointer to previous/next one.
Solution 3. If you know maximum number of elements in vector you may ever have, you can leave all as is, but do one extra thing before pushing very first time - call reserve() on vector with max number of elements as parameters. Vector will allocate array of that size and keep it until it is filled and more space needed. But since you allocated maximum possible size you expect to ever have, reallocation should never happen, and so addresses of objects will remain same.
Choose whichever solution you think fits most for your needs.
#ivan.ukr Offered a number of solutions for keeping the pointers stable. However, I believe that is the wrong problem to solve.
Why do we need stable pointers? So that Class objects can point to the previous object in a container.
Why do we need the pointers to previous? So we can iterate backwards.
That’s the real problem: iterating backwards from a point in the container. The _next pointer is an incomplete solution to the real problem which is iteration.
If you want to iterate a vector, use iterators. You can read about them on the cppreference page for std::vector. I don’t want to write the code for you but I’ll give you some hints.
To get an iterator referring to the ith element, use auto iter = _vec.begin() + i;.
To print the object that this iterator refers to, use iter->print() (you’ll have to rename printAllNext to print and have it just print this object).
To move an iterator backwards, use --iter.
To check if an iterator refers to the first element, use iter == _vec.begin().
You could improve this further by using reverse iterators but I’ll leave that up to you.

C++ Is it possible to leak memory if i'm not using dynamic memory

None of my code uses dynamic memory, but I do have a vector of pointers to a struct called Node, and in my code, I do lose references to those Nodes at one point. The struct looks like this:
struct Node {
int value;
Node* next;
};
I also have a for loop that tries to find the smallest value in my vector of Node pointers by taking the smallest Node off as I go. Here, lists is the vector of Node pointers, and add is the previous smallest value.
for (int i = 1; i < int(lists.size()); ++i) {
if (lists[i]->value <= add) {
add = lists[i]->value;
lists[i] = lists[i]->next;
break;
}
}
I thought I couldn't leak memory if I was just in the stack though...
If the Node referenced in the lists array is dynamically allocated, you should free all of them manually. Otherwise there will be memory leak. You can find more details on https://en.wikipedia.org/wiki/Memory_leak

Creating a Array of Nodes

When we create a array of integers we do it like this:
int main() {
int x;
cout << "Enter size of array"
cin >> x;
int* myArray;
myArray = new int[x]
}
we assign the asterisks next to array, we are assigning it as a array of pointers right?
If I make a array of nodes where:
struct Node {
string Name;
int Age;
}
I ran some code to experiment with it and understand it more and I tried to do just like the array sample but create a array with nodes.
int main() {
Node* sumShit[5];
Node* America = new Node();
America->age = 16;
America->Name = "America";
sumShit[0] = America;
Node* Japan = new Node();
Japan->age = 15;
Japan->Name = "Japan";
sumShit[1] = Japan;
cout << "[" << sumShit[1]->Name << ", " << sumShit[1]->age << "]";
}
Everything printed out fine with pointers but then I did it also without pointers, where I just stored node properties in the Node:
Node myNodeShit[5];
Node Poop;
Poop.age = 16;
Poop.Name = "Poop";
myNodeShit[0] = Poop;
sortArrayName(myNodeShit, 5);
printArray(myNodeShit, 5);
And this also worked, however whats the advantages to using pointers and just storing it within the node. When it comes to algorithms, sorting and using memory, is there a preferred way. Im trying to figure why it would be better to have it as a array of pointers to nodes vs a array of nodes.
Using pointers allows for greater flexibility in updating / modifying existing data because the data is only declared once in memory. From here, you can use pointers to make changes from anywhere in your code.
Additionally, using pointers conserves memory whereas creating the actual nodes will make copies of said node. This becomes apparent when you're passing the array into a function. In this case the array of nodes (without pointers) becomes a local copy pushed onto the call stack. When the function returns, you'll lose any modification you made to the node. Conversely, using pointers will save the node's state.
When in doubt, try to use pointers where you can.

Cannot Dereference Class Object Pointers Inserted Into a Vector

struct Tree_Node
{
typedef int node_value_type;
Tree_Node(node_value_type key) : value(key) {}
public:
node_value_type value = 0;
Tree_Node* right = nullptr;
Tree_Node* left = nullptr;
};
After inserting pointers to the above class into a vector, trying to pop an element and dereference it gives me an ``Access Violation Reading Location'' exception in Visual C++.
vector<Tree_Node*> node_list(2);
Tree_Node* node1 = new Tree_Node(5);
node_list.push_back(node1);
cout << node_list.front()->value;
However, the following works fine:
Tree_Node* node2 = node1;
cout << node2->value << endl;
What am I missing out on here?
Please note that I am adding and accessing the vector elements inside the same scope. Additionally, I am also aware of possible memory leaks and cleaning up. I just wish to know why the above code isn't working
vector<Tree_Node*> node_list(2);
it creates a vector with two null pointers.
node_list.push_back(node1);
it inserts a third element
cout << node_list.front()->value;
it tries to access the first, which is a null pointer
To reserve space without inserting elements use:
vector<Tree_Node*> node_list;
node_list.reserve(2);
But I'm almost sure that the default ctor reserves place for more than 2 elements.
You can also update the two allocated elements:
vector<Tree_Node*> node_list(2);
node_list[0] = node1;
node_list[1] = node2;
And if you want to make sure that your container contains only two elements use an std::pair or (if you can use C++11) an std::array.

C++ Vector of Object , Memory Usage on Empty Object Creation

C++ Vector - part of it to point to same address
Hi , my subject might be confusing.
Here it goes.
I got a vector
struct node{
int nodeid;
vector<string> data;
vector<fTable> fdata;
}
struct fTable{
int index;
int key;
}
vector<node> myNode;
as at some function...
void chord::someFunc(int nodeid)
{
node myTempNode;
vector<string> data1;
vector<fTable> fdata1;
myTempNode.nodeid = nodeid
myTempNode.data = data1;
myTempNode.fTable = ftable1;
myNode.push_back(myTempNode);
myTempNode.clear();
}
I will be creating 10000 objects, at this point of time, i only got the value for nodeid.
But for data and fTable, i am setting to some empty string vector and empty fTable vector but i wonder if i create 10000 objects and doing the same thing.
am i creating 10000 empty string and fTable vector
Is there a way i can set all this object point to same string vector (null value) and fTable vector ( empty value) so i can save some memories. considering i will or might create 10000 nodes or so. and memory consumption is a concern to me.
Thanks for all help.
No, since the vectors are empty, they don't consume much space and no string or fTable objects are created.
Give your limited c++ knowledge I would stay clear of pointers and stick to values.
You don't need to do any of the (immediately) following, the constructor of node takes care of that. This simply overwrites empty vectors with empty vectors.
node myTempNode;
vector<string> data1;
vector<fTable> fdata1;
myTempNode.data = data1;
myTempNode.fTable = ftable1;
If you give your node a constructor like this:
struct node{
int node(int id) : nodeid(id) {}
int nodeid;
vector<string> data;
vector<fTable> fdata;
}
then you only need to write:
myNode.push_back( node(nodeid) );
Creating a vector does not always create its data : the data of a vector is allocated when needed, so vectors with no data will be likely to take sizeof(std:vector<...>) bytes (if reserved size is 0), and vectors with data will in real take sizeof(vector<...>) + n * sizeof(data), where n is the number of reserved items in the vector. The size of a vector is 28 bytes on my implementation.
1st method: vector as fields. The advantage of having vector fields is they're not dynamically allocated, saving you from a bunch of new/delete manual calls : it is more safe.
2nd method: you can also use pointers as you said:
struct node
{
int nodeid;
vector<string>* data; // pointer
vector<fTable>* fdata; // pointer
};
You can set them to 0 (null), saving the size of a vector minus the size of pointer, per node. When you need a node to have a vector, simply new a vector, and set the appropriated pointer. However, this method will eventually take more space than the previous, because it will also take the size of the pointers. And you will have to manage the delete (it can be done with the node destructor, but may be less efficient that deallocating vectors before node destruction).
Conclusion: I suggest you estimate the total size occupied by your data (ex: 10000 * ...), and see if you have to use a specific model (ie, measure first). Personnally, I advise you to take the first (no pointers).
I also recommend that you use a constructor (or two) for node, for a better code.
Yes, use a vector of pointers then, i.e.
struct node {
node(int nid) : nodeid(nid), data(0), fdata(0) { }
int nodeid;
vector<string *> data;
vector<fTable *> fdata;
}
But beware of memory management: now when a node is deleted, the string and the fTable pointed by data and fdata are not deleted. If these data should be owned by a node once assigned, add a destructor:
struct node {
node(int nid) : nodeid(nid), data(0), fdata(0) { }
~node() {
for (auto i = data.begin(); i != data.end(); ++i)
delete *i;
for (auto i = fdata.begin(); i != fdata.end(); ++i)
delete *i;
}
int nodeid;
vector<string *> data;
vector<fTable *> fdata;
}