simple cpp map store and access not working as expected - c++

I have the following code which uses map to insert Nodes into mp according to a key. The class has two functions set and get to insert and access the map respectively.
struct Node {
int value;
int key;
Node(int k, int val):key(k),value(val) {};
};
class Cache {
private:
map<int, Node*> mp;
Node* tail;
Node* head;
public:
void set(int, int);
void get(int);
};
void Cache::set(int key, int value) {
Node newN = Node(key, value);
mp.insert(std::pair<int, Node*>(key, &newN));
}
void Cache::get(int key) {
auto s = this->mp.find(key);
if (s != this->mp.end()) {
Node *nHit = s->second;
std::cout << "Map key = " << s->first;
std::cout << " : Node Key = " << nHit->key;
std::cout << ", value = " << nHit->value << "\n";
}
}
A driver main function implementation is below, which takes input of 2 lines and outputs key and value.
int main() {
int i;
Cache l;
for(i = 0; i < 2; i++) {
string command;
cin >> command;
if(command == "get") {
int key;
cin >> key;
l.get(key);
}
else if(command == "set") {
int key, value;
cin >> key >> value;
l.set(key, value);
}
}
return 0;
}
Input -
set 2 3
get 2
Output -
Map key = 2 : Node Key = 32764, value = -491659096
Note - The output key and value keeps changing and are not fixed with each run.
Why and how is the key and value getting changed for the map here?

You are inserting a pointer to a function-scoped value. When the function set() exits the value newN is destroyed, and the pointer held in the map is invalid.
Either you really want a map with an instance of Node as the value; or you need to use new in set() to allocate your object, but then you also need to remember to delete it. You could use "smart" pointers such as shared_ptr or unique_ptr to help manage this lifetime - though unique_ptr won't get you any advantages over using an instance.

In C++, a piece of data is typically tied to a single location. If that location is a variable in some { block scope; }, then the variable is deleted at the closing }. For instance, the closing bracket of Cache::set deletes newN, and any references to it (including pointers in mp) no longer point anywhere.
C++ has a second option: the lifetime of some data can be controlled by a class. For instance, the int and Node* values you put in mp get deleted along with mp. So rather than storing Node* in mp, you can store Node directly, instead of its address!
The declaration of mp should be
map<int, Node*> mp;
You can insert with
void Cache::set(int key, int value) {
mp.emplace(key, Node(key, value));
}
And then in main you can have
Node &nHit = s->second;
And then you can get members of nHit with . instead of ->.
Your other alternative is to use smart pointers, as Jesper Juhl mentioned. Store std::unique_ptr<Node> in mp if you're using pointers only for polymorphism with virtual methods, and std::shared_ptr<Node> is useful if you want some of your Node objects to be used in several places and mp.
Taking the address of an object with & (e.g. to create Node*) is very useful if you want to just reference an object of known lifetime, and you want to store that reference inside of some other object of a shorter lifetime.
DO NOT use new Node(key, value) except in a smart pointer constructor, unless you're prepared to individually delete every Node* yourself, and never make mistakes.

You have to allocate Node using new. E.g.,
Node *newN = new Node(key, value);
mp.insert(std::pair<int, Node*>(key, newN));
As it is your Node is on the stack and goes out of scope when the function returns.

Related

Use the fields of a struct while also using its address

struct nod {
std::pair<int, int> matrixPos;
nod *anteriorNode;
nod(std::pair<int, int> matrixPos)
{
matrixPos = matrixPos;
anteriorNode = nullptr;
} //this is for the first node
nod(std::pair<int, int> matrixPos, nod* anteriorNode)
{
matrixPos = matrixPos;
anteriorNode = anteriorNode;
}
};
void expandNode(std::queue<nod> &coada, int **matrice, nod& nodToExpand)
{
if (matrice[nodToExpand.matrixPos.first-1][nodToExpand.matrixPos.second] == 0)
{
nod newNode = nod(std::pair<int, int>(nodToExpand.matrixPos.first - 1, nodToExpand.matrixPos.second), nodToExpand);
}
}
I have some nodes that I need to link together (so I know which is the parent of each node) while also accessing their values.
I need to acess their matrixPos fields for the values needed in the if statement, while I also need
their address for the field 'anteriorNode'.
How can I do this and what is the most efficient way?
If all you are trying to do is obtain a pointer to nodToExpand from within the expandNode function, you can do so by getting its address. References can be used as if they where the referred object itself, that's their whole deal.
All you need is a good old &nodToExpand.

How to avoid using new operator in C++?

I have a C++ program that creates Huffman codes for all characters in file. It works good, but I want to create nodes without using new operator because I know that you shouldn't use it. I tried using a vector global variable for saving nodes but that doesn't work.
std::vector<Node> nodes;
Node* create_node(unsigned char value, unsigned long long counter, Node* left, Node* right) {
Node temp;
temp.m_value = value;
temp.m_counter = counter;
temp.m_left = left;
temp.m_right = right;
nodes.push_back(temp);
return &nodes[nodes.size() - 1];
}
Edit: I added more code, I did't really explained what doesn't work. Problem is in generate_code(), it never reaches nullptr. I also tried using Node and not Node* but the same thing happened.
void generate_code(Node* current, std::string code, std::map<unsigned char, std::string>& char_codes) {
if (current == nullptr) {
return;
}
if (!current->m_left && !current->m_right) {
char_codes[current->m_value] = code;
}
generate_code(current->m_left, code + "0", char_codes);
generate_code(current->m_right, code + "1", char_codes);
}
void huffman(std::ifstream& file) {
std::unordered_map<unsigned char, ull> char_frequency;
load_data(file, char_frequency);
std::priority_queue<Node*, std::vector<Node*>, Comparator> queue;
for (auto& node : char_frequency) {
queue.push(create_node(node.first, node.second, nullptr, nullptr));
}
while (queue.size() != 1) {
Node* left = queue.top();
queue.pop();
Node* right = queue.top();
queue.pop();
auto counter = left->m_counter + right->m_counter;
queue.push(create_node('\0', counter, left, right));
}
std::map<unsigned char, std::string> char_codes;
Node* root = queue.top();
generate_code(root, "", char_codes);
for (auto& i : char_codes) {
std::cout << +i.first << ": " << i.second << "\n";
}
}
The general answer is of course to use smart pointers, like std::shared_ptr<Node>.
That said, using regular pointers is not that bad, especially if you hide all pointers from the outside. I wouldn't agree with "you shouldn't use new", more like "you should realize that you have to make sure not to create a memory leak if you do".
In any case, for something like you do, especially with your vector, you don't need actual pointers at all. Simply store an index for your vector and replace every occurence of Node* by int, somewhat like:
class Node
{
public:
// constructors and accessors
private:
ValueType value;
int index_left;
int index_right;
}
I used a signed integer as index here in order to allow storing -1 for a non-existent reference, similar to a null pointer.
Note that this only works if nothing gets erased from the vector, at least not before everything is destroyed. If flexibility is the key, you need pointers of some sort.
Also note that you should not have a vector as a global variable. Instead, have a wrapping class, of which Node is an inner class, somewhat like this:
class Tree
{
public:
class Node
{
...
};
// some methods here
private:
vector<Node> nodes;
}
With such an approach, you can encapsulate your Node class better. Tree should most likely be a friend. Each Node would store a reference to the Tree it belongs to.
Another possibility would be to make the vector a static member for Node, but I would advise against that. If the vector is a static member of Node or a global object, in both cases, you have all trees you create being in one big container, which means you can't free your memory from one of them when you don't need it anymore.
While this would technically not be a memory leak, in practice, it could easily work as one.
On the other hand, if it is stored as a member of a Tree object, the memory is automatically freed as soon as that object is removed.
but I want to create nodes without using new operator because I know that you shouldn't use it.
The reason it is discouraged to use new directly is that the semantics of ownership (i.e. who is responsible for the corresponding delete) isn't clear.
The c++ standard library provides the Dynamic memory management utilities for this, the smart pointers in particular.
So I think your create function should look like follows:
std::unique_ptr<Node> create_node(unsigned char value, unsigned long long counter, Node* left, Node* right) {
std::unique_ptr<Node> temp = std::make_unique<Node>();
temp->m_value = value;
temp->m_counter = counter;
temp->m_left = left;
temp->m_right = right;
return temp;
}
This way it's clear that the caller takes ownership of the newly created Node instance.

Memory allocation In Tree

Hello everyone i wish you are having a great day, i have a problem with allocation memory for my tree with some code i think it's easier to explain and understand.
#define H 7
class Node{
public:
int node_number;
int depth;
int value;
Node* nodes[L];
public:
Node new_node(int node_number,int depth,int value);
void add_node(Node root_node,Node new_node);
void print_node(Node print_node);
};
To create a node my function is here
Node Node::new_node(int node_number,int depth,int value){
Node x;
x.node_number=node_number;
x.depth=depth;
x.value=value;
x.nodes[L]=(Node*) std::malloc(L*sizeof(Node));
return x;
}
and now when i want to add nodes in the node him self like declared in the class i got Segmentation fault (core dumped)
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=&(new_node);
}
My main function
Node root_node;
root_node=root_node.new_node(10,2,23);
Node x;
x=x.new_node(17,19,7);
root_node.add_node(root_node,x);
root_node.print_node(root_node);
Thank you so much
There are few problems here. Firstly you're not actually allocating any new memory. The line in the new_node method
Node x;
is a local variable so it will be destroyed when the method completes, the method then returns a copy of this object on the stack.
Then in the add_node method there is another problem:
root_node.nodes[0]=&(new_node);
This line doesn't call the node_node method, it actually takes the address of the function. Even if it did call the method it would be returning a copy of the object on the stack not a pointer to an object on the heap which is what you need.
Your code doesn't show the definition of L, I'm going to assume that it is a macro definition. Your new_node method should look like this, node the new reserved word, this is where the new object is created on the heap:
Node* Node::new_node(int node_number,int depth,int value){
Node *x = new Node;
x->node_number=node_number;
x->depth=depth;
x->value=value;
// x->nodes[L]=(Node*) std::malloc(L*sizeof(Node));
// not needed if L is a macro and needs correcting if L is a variable
return x;
}
Now this method returns a pointer to a new object on the heap.
Your add_node method will then look like this:
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=new_node(/* Need to add params here! */);
}
However there is a much better way of doing what you want here. You should write a constructor for the Node class like below:
Node::Node(int node_number,int depth,int value)
{
this->node_number = node_number;
this->depth = depth;
this->value = value;
}
This removes the need for the new_node method and means your add_node method will look like this:
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=new Node(/* Need to add params here! */);
}
Hope this helps.
Although there is already a complete answer provided by PeteBlackerThe3rd, I deem it worthy to also provide an answer that does not use any manual memory allocation as this is often the preferred way in C++.
I took the liberty to make some minor adjustments, e.g., when adding a node it is not necessary to provide the depth in the tree as this can be derived from its parent's node.
The struct uses a std::vector which has (at least) two benefits compared to the code provided in the question. First, there is no need to know the maximum number of children nodes during compile time. If you want to fix this during compile time one can easily replace the std::vector by std::array. Second, there is no need to manually free memory at destruction as this is all taken care of by std::vector.
#include <iomanip>
#include <vector>
struct Node
{
// I expect these data members to be constants
int const d_nodeNumber;
int const d_depth;
int const d_value;
std::vector<Node> d_childNodes;
Node() = delete;
Node(int number, int depth, int value)
:
d_nodeNumber (number),
d_depth (depth),
d_value (value),
d_childNodes ()
{ }
/*
* Note that this function does not ask for a 'depth' argument
* As the depth of a child is always the depth of its parent + 1
*/
void addChildNode (int number, int value)
{
d_childNodes.emplace_back(number, d_depth + 1, value);
}
/*
* Just an arbitrarily function to generate some output
*/
void showTreeFromHere() const
{
int const n = 1 + 2 * d_depth;
std::cout << std::setw(n) << ' '
<< std::setw(5) << d_nodeNumber
<< std::setw(5) << d_depth
<< std::setw(5) << d_value << std::endl;
for (Node const &n: d_childNodes)
n.showTreeFromHere();
}
};
The struct can be used as follows:
int main()
{
Node root_node(0,0,0);
// Add two child nodes
root_node.addChildNode(1,1);
root_node.addChildNode(2,1);
// Add six grandchildren
root_node.d_childNodes[0].addChildNode(3,8);
root_node.d_childNodes[0].addChildNode(4,8);
root_node.d_childNodes[0].addChildNode(5,8);
root_node.d_childNodes[1].addChildNode(6,8);
root_node.d_childNodes[1].addChildNode(7,8);
root_node.d_childNodes[1].addChildNode(8,8);
root_node.showTreeFromHere();
}

Pointers in linked list not working as expected

This realization of linked list is broken. Address of nodes[0].next doesn't match the nodes[1] address. So nodes[1].next is NULL (as default value). I added some address printing to the search method. It looks like the nodes[1] wasn't initialized?
#include <iostream>
#include <vector>
using namespace std;
typedef struct Node_T {
int data;
Node_T *next;
} Node;
class LinkedList{
public:
vector<Node> nodes;
LinkedList(){
}
void insert(int data) {
Node temp_node;
temp_node.data = data;
temp_node.next = NULL;
size_t len = nodes.size();
nodes.push_back(temp_node);
if (len > 0) {
nodes[len - 1].next = &nodes[len];
}
}
int search(int val){
if (nodes.empty())
return -1;
Node *node_ptr = &nodes[0];
// Debug
cout << &nodes[1] << "\n";
cout << &nodes[0].next << "\n";
int i = 0;
do {
if (node_ptr->data == val) return i;
i++;
} while((node_ptr = node_ptr->next) != NULL);
return -1;
}
};
int main()
{
LinkedList llist;
llist.insert(1);
llist.insert(2);
llist.insert(3);
llist.insert(4);
llist.insert(5);
cout << llist.search(3) << "\n";
return 0;
}
It shows me: 0x8e6a060 0x8e6a05c -1
When you add elements to a vector, references to (and hence addresses of) vector elements are invalidated. You must therefore not use values such as &nodes[0] or &nodes[len], as they are meaningless.
The point with an exercise like this is to get the hang of the internal structure in a linked list. You have replaced that internal structure with a vector<Node>.
Instead of a vector, the idea is to have a
private:
Node* head;
As you data member.
In your insert function you are supposed to dynamically allocate memory for the Node with
Node* newNodePointer = new Node;
And manipulate the pointer with next and such.
It is worth to point out, that this is fine as an exercise, but your "real" code should use standard library facilities.
First, Your printout is incorrect: this line
cout << &nodes[0].next << "\n";
prints the address of next, rather than printing the next itself. Changing to
cout << nodes[0].next << "\n";
gives the correct printout (demo).
However, the main issue is that you keep pointers to elements of std::vector. These become invalid after the first write, because new storage gets allocated for the growing vector.
You can certainly work around this by reserving sufficient space upfront (call nodes.reserve(1000) from the constructor of your list; demo) but that is merely a hack: you should use new and delete to allocate elements of your linked list manually. That is the whole point of this exercise.
But I still need a container to ensure that nodes will be live as expected?
No, you do not. Your class is a container. By referencing the whole chain of nodes from the head pointer it can ensure that the entire chain is kept "live".

C++ binary search tree

Recently I have started playing around with C++, namely classes and pointers. I looked around for similar questions, but nothing helped.
I have a binary search tree class that holds some information in string format (well, char *), but after adding a new node to the tree, I cannot get the information back, as it returns junk.
Here is what my code looks like:
class Node
{
Node *lNode;
Node *rNode;
char *name;
public:
void setName(char *n) { name = n; }
char *getName() { return name; }
}
class Tree
{
Node *root;
Node *addNode(Node *, Node *);
public:
Tree() { root = NULL };
int addNewNode(Node *);
void print();
};
int Tree::addNewNode(Node *n)
{
root = addNode(root, n);
cout << root->getName() << endl; // this returns the name correctly
}
Node *Tree::addNode(Node *subtree, Node *node)
{
if(subtree== NULL)
{
subtree = node;
}
else if(node->getName() <= subtree->getLeft())
{
subtree->setLeft(addNode(subtree->getLeft(), node));
}
else
{
subtree->setRight(addNode(subtree->getRight(), node));
}
return subtree;
}
void Tree::print()
{
cout << root->getName() << endl; // this does not!
}
And this is where I call the methods:
Tree *myTree = new Tree();
Node *n = new Node();
n->setName(name);
myTree->addNewNode(n);
The tree variable is a private member attribute of an outer container class, and actually gets created outside that class to be passed into the constructor. When I invoke the addNewNode method, that adds a Node to the tree, but when I want to print out the name of the node stored in the root, it just comes up with junk. I guess there's a haywire pointer somewhere, but I cannot find it for the life of me.
Any help would be greatly appreciated.
I'll guess that you're passing in a string pointer name to setName and just copying the pointer to name (as opposed to reallocating and saving the string). Later, the original object is gone, and your object name is left pointing to garbage. Trying using std::string for name instead, or create your own memory with name = new char[ strlen(n) + 1 ] and strcpy/memcpy it in. And don't forget to delete [] name at object destruction if you go that route.
When root is null, you set it to city rather than node. There's your problem.