C++: where are my new nodes? - c++

I am trying to add element in a Set using Binary Tree:
bool TreeSet::add(const string &str)
{
if (treesize == 0)
{
TreeNode->data = str;
treesize++;
return true;
}
else
{
if (str < TreeNode->data)
return insert(TreeNode->left, str);
else if (str > TreeNode->data)
return insert(TreeNode->right, str);
else
return false;
}
return false;
}
bool TreeSet::insert(TREE *node, const string &str) //private
{
if (node == NULL)
{
node = new TREE;
node->data=str;
node->left = NULL;
node->right = NULL;
treesize++;
return true;
}
else
{
if (str < node->data)
return insert(node->left, str);
else if (str > node->data)
return insert(node->right, str);
else
return false;
}
return false;
}
As you can see, I want to initialize a TREE struct inside of insert and when I finish doing this I want to link it with the left or right node of the tree.
But when I gdb this, only 1 level of tree (top level) can be constructed, the *left and *right node are NULL no matter how many strings I was trying to add to it. Why?
My TREE is:
typedef struct tree
{
string data;
tree *left;
tree *right;
} TREE;

bool TreeSet::insert(TREE *node
should be
bool TreeSet::insert(TREE *&node
Pointers can also be passed by reference, and should be if you intend to modify them directly. Otherwise you pass by copy and you now have two pointers pointing at the same location. When you use the copied one to new up some data, it now points to a new memory location, leaving your original pointer still as NULL (nullptr in C++11)
On a side note, when a tree gets constructed, you should probably initialize left and right to NULL (nullptr in C++11):
typedef struct tree
{
string data;
tree *left;
tree *right;
tree():left(NULL),right(NULL){}
} TREE;

When you pass a pointer as a parameter in the function insert like this:
bool TreeSet::insert(TREE* node, const string& str);
then the pointer is copied into the argument node. Pointing node to something else only points the local copy of the pointer. The pointer passed to the function from the call site is unchanged.
node = new TREE; // Points local variable 'node' to newly allocated data.
// When the function goes out of scope 'node' will be destroyed
// and the memory will be leaked.
To change where the original call site pointer points, take the parameter by reference (or add another level of indirection):
bool TreeSet::insert(TREE*& node, const string& str);
By taking a parameter by reference, you make sure you are accessing the call site variable and not a local copy.

Related

Returning a pointer or reference to my current object from a insert_node function in a linked list program

I'm a beginner in c++. and I was writing a link list in which I can call my function for inserting nodes like this:
(assuming a and b and c are data which I want to insert in link list.
list.insert(a)->insert(b)->insert(c);
and I did it like this:
#include <iostream>
using namespace std;
class Node {
public:
char letter;
Node* next;
};
class link_list {
private:
Node* head;
public:
link_list() {
head = NULL;
}
link_list* insertNewNode(char item);
};
link_list* link_list::insertNewNode(char item) {
Node* temp;
temp = new Node;
temp->letter = item;
temp->next = head;
head = temp;
return this;
}
int main() {
link_list list;
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
in my insertNewNode function I'm returning a pointer to my current object.and it's working fine ,however I'm not sure if my method is right?
But I should also explain what happen , if instead of returning a pointer or reference to my current object ,I return my current object.
so I tried this:
class Node {
public:
char letter;
Node* next;
};
class link_list {
private:
Node* head;
public:
link_list() {
head = NULL;
}
link_list insertNewNode(char item);
};
link_list link_list::insertNewNode(char item) {
Node* temp;
temp = new Node;
temp->letter = item;
temp->next = head;
head = temp;
return *this;
}
int main() {
link_list list;
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
and then I received an error which said list should be a pointer ,so I changed my main to:
int main() {
link_list *list;
list = new link_list;
list->insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
but I'm still receiving this error which said here list->insertNewNode('a')->insertNewNode('b')->insertNewNode('c'); expression must have a pointer type and these two errors:
1.type 'link_list' does not have an overloaded member 'operator ->'
2.'->link_list::insertNewNode': left operand has 'class' type, use '.'
so here is my questions for purpose of calling insert function like this list.insert(p1)->insert(p2)->insert(p3);, is my way in first program right ? and also is it even possible to return my current object for this purpose? and what would happen if I return current object?
PS:sorry for long question and also thanks in advance for your help.
Well, there's nothing criminal in your current method returning a pointer. Not something done very often, still quite compilable.
More idiomatic would be to return current object by-reference:
link_list &insert(char elem) {
return *this;
}
Your initial problem was that you changed method's return type, but retained -> in main(). If you change insert's return type to reference from pointer, then chained calls should be done via ., as you're working with objects and references to them, not with pointers.
Returning a copy of current object from a setter is not something that should be done, especially if you manage private resources on your own and haven't defined a proper copy constructor yet. Rather return a reference.
Your method seems fine. You are doing
link_list* insertNewNode(char) {
// ...
return this;
}
so that you can chain the insertions like this
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
You could also return a reference to the link_list, like this
link_list& insertNewNode(char) {
// ...
return *this;
}
and now chaining the insertions looks like this
list.insertNewNode('a').insertNewNode('b').insertNewNode('c');
Note that you shouldn't do something like
link_list insertNewNode(char) {
// ...
return *this;
}
because this will compile, but you would be returning a copy of the linked list, and the chaining would simply not work.
If your nodes would be added to the tail, the default copy constructor would make it appear as if chaining works, because the original link_list would see all Nodes added to the copy.
In your implementation, you are adding Nodes at the head, so the original link_list doesn't see Nodes added to the copy, and so the chaining doesn't appear to work. This is good, because the copies would leak the memory they allocate, even if you write a proper destructor.

How to return pointer to object in an array?

I'm using assimp to process some 3d models, and I'm iterating through child nodes from an arbitrary parent node, looking for a node with a matching string name. As the children as stored as an array, I need to return a pointer to the node at the Nth index in the array if the name matches. I have successfully found the name by matching the strings and printing them out to a FILE object(assf), however attempting to exit early by returning the pointer to the matching node, always returns 'nullptr'.
I've tried declaring a global variable to store a temporary node pointer, and copy the pointer of the matching node to the temporary pointer when a match is found. This actually does work, but It isn't the solution I'm looking for, especially when I feel like I have some fundamental misunderstanding of recursive functions and their return values. Or more.
const aiNode* fn2(const aiNode* nin, const aiString& name){
for(unsigned int c = 0; c < nin->mNumChildren; c++){ //for every child of the node argument...
if (nin->mChildren[c]->mName == name){ //...compare the names, and if successful enter this block
fprintf(assf, "Found node '%s'!\n",name.C_Str());
return nin->mChildren[c];//This IS the node i want, so why does it return null ?
}
else{ //The name of this node doesn't match what I'm looking for, try the next node. Repeat...
fn2(nin->mChildren[c], name);//This WILL return the node if made called as: return fn2(nin->mChildren[c], name);
}
}
fprintf(assf, "Node name (%s) not a match\n",nin->mName.C_Str());
return nullptr;//None of the child nodes of the node passed in have a matching name!
}
The expected result, when the name matches, is the pointer to the current node in the array is returned and used by the calling function. The actual result is that I'm always returning a nullptr.
Edit;
Thank you Soronel and Jonathan, that makes sense and helped me come up with a working solution. By adding a temp to the function, the following code now performs as expected;
for (unsigned int c = 0; c < nin->mNumChildren; c++) { //for every child of the node argument...
const aiNode* tmpnode = nullptr; //const aiNode* tmpnode = nullptr; //Store pointer to a temp node no matter what
if (nin->mChildren[c]->mName == name) { //...compare the names, and if successful enter this block
fprintf(assf, "Found node '%s'!\n",name.C_Str());
tmpnode = nin->mChildren[c]; //This IS the node i want, assign it to the temp
}
else { //The name of this node doesn't match what I'm looking for, try the next node. Repeat...
tmpnode = fn2(nin->mChildren[c], name); //Call this function recursively, and store it's result in the temp
}
if(tmpnode) return tmpnode; //Return the matched node here, OR nullptr at end of function if no match
}
fprintf(assf, "Node name (%s) not a match\n",nin->mName.C_Str());
return nullptr; //None of the child nodes of the node passed in have a matching name!
}
Your recursive call does not return the found value (if any):
fn2(nin->mChildren[c], name);
needs to be something like:
const aiNode* ptr = fn2(nin->mChildren[c], name);
if(ptr)
return ptr;
The direct function call where the node is found is fine, it is how it is passed back up the call chain that is the problem.

c++14 unique_ptr and make unique_ptr error use of deleted function 'std::unique-ptr'

I have a function like this..
unique_ptr<Node> test(unique_ptr<Node> &&node, string key)
{
if(!node)
{
return make_unique<Node>(key);
}
else
return node;
}
I want to create a node if the node is null, or to return the node. but it errors out saying "use of deleted function 'std::unique_ptr' ". What have I done wrong?
The problem is the way you are calling the function. But first of all you should accept your std::unique_ptr by value, not r-reference.
Then you need to std::move() your pointer when calling the function:
// accept by value
std::unique_ptr<Node> test(std::unique_ptr<Node> node)
{
if(!node)
return std::make_unique<Node>();
return node;
}
int main()
{
auto n = std::make_unique<Node>();
n = test(std::move(n)); // move the pointer
}
A std::unique_ptr can't be copied otherwise it would not be unique. You hav to move them.

C++ no known conversion for argument 1 from ‘Node*’ to ‘Node*&’

I am trying to use a recursive function to insert nodes into a binary search tree. However, when I try to call my function, I get the error message
no known conversion for argument 1 from ‘Node*’ to ‘Node*&’
This is the code for the recursive function and the function that calls it:
bool BST::add(int data)
{
if (root == NULL)
{
Node* gnu = new Node(data);
root = gnu;
return true;
}
return recursiveAdd(root, data);
}
bool BST::recursiveAdd(Node*& start, int data)
{
if (start == NULL)
{
Node* gnu = new Node(data);
start = gnu;
return true;
}
if (data < start->getData())
{
return recursiveAdd(start->getLeft(), data);
}
if (data > start->getData())
{
return recursiveAdd(start->getRight(), data);
}
if (data == start->getData())
{
return false;
}
return false;
}
The following are the functions for getLeft(), getRight(), and getData() from my Node class:
int Node::getData()
{
return data;
}
Node* Node::getLeft()
{
return leftChild;
}
Node* Node::getRight()
{
return rightChild;
}
I would really appreciate it if someone could show me what I need to fix for it to work properly.
Thanks!
You can't bind a temporary variable (the copies returned by getLeft and getRight) with a non-const lvalue reference, hence the error.
You shouldn't need to modify the pointer itself anyway. I'd suggest you rewrite your algorithm to work without this rather strange and error-prone requirement.
Your accessors return copies of the internal pointers
Node* Node::getLeft()
{
return leftChild;
}
Node* Node::getRight()
{
return rightChild;
}
But recursiveAdd needs to be able to modify the structure
start = gnu;
These approaches aren't compatible, and you were lucky the compiler caught you. You can either change getLeft() and getRight() to return references, or capture the structure change made by recursiveAdd() and propagate it using a mutator.
Node* theLeft = start->getLeft();
bool did_insert = recursiveAdd(theLeft, data);
start->setLeft(theLeft);
return did_insert;
Or, as Matt says, you can make recursiveAdd a friend and just do
return recursiveAdd(start->leftChild, data);
...
if (root == NULL)
{
Node* gnu = new Node(data);
root = gnu;
return true;
}
return recursiveAdd(root, data);
}
Block scope. If root is NULL, you're going to end up with no declaration for root outside of the block. This means that recursiveAdd() will be called with an invalid parameter; this cannot compile or else it would always have the opportunity to yield undefined behavior.
Regardless, since root will expire, so will the reference, as the reference will point to a temporary object. This is incorrect, as references cannot be bound to temporary objects--they, by definition, will point to "containers of values," often called lvalues in C++11 parlance.
There are also rvalues, but that is outside the scope of the question.

how to design const member function, preventing it from modifying the object

This a const member function, which allow me to get the minimum node of the tree:
BinarySearthTree* BinarySearchTree::min() const
{
// Return the minimum node (left-most node) value of the tree
BinarySearchTree * next = (BinarySearchTree *) this;
for (next ; next != NULL; next = next->pLeft)
if (next->pLeft == NULL)
return next;
}
I have to cast down the const-ness of 'this' pointer when assigning it to 'next', but this actually rises the potential that I may modify the value of what 'this' points to? Rather than always remind myself not to modify whatever 'next' points to, is there a way to prevent it happening by a better designing of the function?
Make next const:
const BinarySearthTree* BinarySearchTree::min() const
{
// Return the minimum node (left-most node) value of the tree
const BinarySearchTree *next;
for (next = this; next != NULL; next = next->pLeft)
if (next->pLeft == NULL)
return next;
return NULL;
}
If you don't want the contents to be modified, then you should make min() return a pointer to a const object.
Your next variable should also be a pointer to a const object, therefore.
Here is how I think your method should look:
const BinarySearchTree* BinarySearchTree::min() const
{
// Return the minimum node (left-most node) value of the tree
for (const BinarySearchTree* next = this; next != NULL; next = next->pLeft)
{
if (next->pLeft == NULL)
{
return next;
}
}
return this;
}
Also, in C++, you should avoid C-style casts. The const_cast exists for this purpose:
BinarySearchTree* next = const_cast<BinarySearchTree*>(this);
But that is not necessary in this instance.