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.
Related
I am trying to create a graph using linked list styled nodes where each node is a structure containing a key and an address to the next node, but I want to join multiple nodes to one node so I tried creating an array of pointers to structure and initialize them using new dynamically but it throws an error saying that it "cannot convert node*** to node** in assignment".
I have tried using struct node* next[] but it didn't work well. What am I missing here? Should I just use a vector of pointers instead of an array?
struct node
{
int key;
struct node** next;
};
int main()
{
struct node A;
A.key = 12;
A.next = new node**[2];
return 0;
}
Should I just use a vector of pointers instead of an array?
This is often an ideal solution. This would fix the memory leak that your program has (or would have if it compiled in the first place). An example:
struct node
{
int key;
std::vector<node*> next;
};
// usage
A.next.resize(2);
Vector does have space overhead, which can be a problem with big graphs because the total overhead increases linearly in relation to number of nodes. If vector is not appropriate for you, an alternative is std::unique_ptr, which does not have any overhead compared to a bare pointer:
struct node
{
int key;
std::unique_ptr<node[]> next;
};
// usage
A.next.reset(new node*[2]);
new node**[2];
What am I missing here?
You're attempting to create an array of node** when you need an array of node*.
Should I just use a vector of pointers instead of an array?
YES!
After including the vector library, then in your structure, you would have a member like this:
std::vector<node*> next;
This is the C++ approach, using raw pointers is the C approach.
As an encyclopedian information though, with raw pointers, you would do:
A.next = new node*[2];
which means an array of two pointers.
So I'm trying to write a function that places all of the values of a binary tree into a vector, which will later be used to recreate it. But when I try to call this function, I get an error:
Error in `./bst': double free or corruption (fasttop):
This is the function I'm using. The vector itself is a private variable containing nodes. size() returns the size of the tree and is working.
void BST::swapvector()
{
Node *ptr = m_root;
while (size() != 0)
{
if (ptr->m_left != NULL) {
ptr = ptr->m_left;
} else if (ptr->m_right != NULL) {
ptr = ptr->m_right;
} else {
Node *temp = ptr;
myvector.push_back(ptr); //starting from root, we traverse until we reach the bottom and then add ptr to the vector
ptr = m_root;
delete temp; //once we're finished, we delete temp
}
}
}
Does anyone know why this isn't working? Thanks!
It's obvious why this isn't working.
} else {
Node *temp = ptr;
myvector.push_back(ptr); //starting from root, we traverse until we reach the bottom and then add ptr to the vector
ptr = m_root;
delete temp; //once we're finished, we delete temp
}
You're storing a pointer to Node into vector and then deleting that Node with delete temp. After that pointer stored into vector points to garbage or non-existent memory.
"...a function that places all of the values of a binary tree into a vector..."
No, you're not storing binary tree values, you're storing pointers to binary tree values (Node objects).
There are two things you can do:
If the binary tree will not be freed nor changed for the lifetime of myvector then you can just remove the delete temp; line.
If assumption in the first case is not true, then you need to store Node elements into vector, not pointers to them. So, define myvector as vector<Node> myvector; instead of vector<Node *> myvector; and change myvector.push_back(ptr); to myvector.push_back(*ptr);.
You cannot delete temp after you place it a vector. Also, how is your vector defined? There might be problem there.
Also you should use iterators instead of push_back() function. It doesn't work well with pointers.
And, why does everyone insist on using c-style pointers. Use shared or unique pointers. Please?
Type of error usually signifies that a pointer being freed twice.
So I currently have a simple struct (linkedlist) that I will be using in a HashMap:
struct Node {
std::string key, value;
Node* head;
}
I'm currently trying to dynamically allocate an array with pointers to each struct. This is what I have right now ...
Node* nodes = new Node[100]
I understand this allocates an array of 100 nodes into memory (which I will have to delete later on); however, upon iteration to try to transverse these nodes (which I an implementing as a linked list)...
for (int x = 0; x < 100; x++) {
Node current = nodes[x]; // Problem is I wanted an array to node pointers. This is not a pointer.
while (current != nullptr) { // this isn't even legal since current is not a pointer.
// DO STUFF HERE
current = current.next; // This is not a pointer access to a method. I'm looking to access next with current->next;
}
}
Hopefully I was clear enough. Can someone how to allocate a dynamic array of pointers to structs? So far I'm able to dynamically allocate an array of structs, just not an array of pointers to structs.
There are two approaches. Either you allocate an array of structures and introduce one more pointer that will point to the element in the array that will play the role of the head.
For example
Node *head = nodes;
(in this case head points to nodes[0])
After the list will not be needed you have to delete it using operator
delete [] nodes;
Or you can indeed to allocate an array of pointers to the structure like this
Node **nodes = new Node *[100];
But in this case each element of the array in turn should be a pointer to a dynamically allocated object;
And to delete the list you at first have to delete each object pointed to by elements of the array for example in a loop
for ( int i = 0; i < 100; i++ ) delete nodes[i];
and then to delete the array itself
delete [] nodes;
It is a good idea to initialize each element of the array with zeroes when the array is allocated for example
Node **nodes = new Node *[100]();
I suggested you this structure:
class myList {
struct Node {
string value;
Node* next;
}
/*Public methods .. Add/Set/Get/Next/isEmpty.. etc ... */
Node* head, *tail;
};
in main:
myList* lis = new myList[number];
then you have number of lists! and do all work in class by method's and operators, like if you want the next node just call lis[0].getNext();
if you want to skip current node dolis[0].Next(); ... etc ..
this how to work, what you try to do is looks like C program!
////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)
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.