Trying to search for a specific Node in a Tree, and I need to return a pointer to the Node when I've found it. The nodes are of a derived class type called BudgetEnvelope, and the error that I'm getting reads:
Cannot initialize return object of type BudgetEnvelope with an lvalue of type Node<BudgetEnvelope>
template <class T>
T* Tree<T>::find( Node<T> * ptr, T value){
if(ptr != NULL){
if(ptr->value == value){
return ptr; <------error is on this line
}
else{
if(value < ptr->value){
return find(ptr->left, value);
}
else{
return find(ptr->right, value);
}
}
}
else{
return NULL;
}
}
My understanding was that since the nodes are of the same type as the pointer that I am returning, that it should work. How can I resolve this?
Edit: More information.
When I change the return type to Node<T>*, the file where I am using this method gives me another error.
void EnvelopeBox::deposit(int id, double amount){
BudgetEnvelope searchKey = *new BudgetEnvelope(id, "searchKey");
BudgetEnvelope* keyPtr = envelopes.find(searchKey); <----same error
keyPtr->deposit(amount);
}
The deposit method is defined inside the BudgetEnvelope class, not Node, so if I change keyPtr to be the same type Node<T>*, I can't access the deposit method.
ptr is a pointer to type Node<T> and the function returns a pointer to type T. Types T and Node<T> are different.
If you want to return a T* you should return whatever method in your Node class returns a pointer to the value contained in that Node. Otherwise, which i think is what you want, change the signature of T* Tree<T>::find( Node<T> * ptr, T value) to return Node<T>*, as Justin suggested.
I think you want to return Node<T>* not T* because ptr is of type Node<T>*
e.g.
Node<T>* Tree<T>::find( Node<T> * ptr, T value)
EDIT:
With the new information you provided, what you need to do is convert
BudgetEnvelope* keyPtr = envelopes.find(searchKey);
to
Node<BudgetEnvelope>* keyPtr = envelopes.find(searchKey);
then to access the data inside, you do the following:
BudgetEnvelope myValue = keyPtr->Value;
myValue.deposit(amount)
What you need to do is access the data inside the node.
Alternatively, you can return ptr->Value from your find function.
Related
I am building a data structure and need to manipulate the object indicated by a pointer. The object indicated by the pointer is:
//in header file
struct treeNode{
int value;
treeNode* left;
treeNode* right;
};
My current implementation only changes what the pointer is pointing to.
target->value = oneLarger->value
Target and oneLarger are defined:
void method(treeNode* target){
treeNode* oneLarger = (tree node retrieved by another method)
target->value = more->value
}
Is this possible to do via pass by reference or do I have to pass by value?
You can do: by Pointer, by Ref, by Copy
note that changes made in the byCopy function will get lost as soon as the function is done!
Those options look like:
//by Pointer
void method(treeNode* target) {
treeNode* oneLarger = ...
target->value = oneLarger->value;
}
//by Ref
// since that is a ref, you access the value using the dot(.) and not the `->` operator
void method(treeNode& target) {
treeNode* oneLarger = ...
target.value = oneLarger->value;
}
//by Copy
// since that is a copy, you access the value using the dot(.) and not the `->` operator
void method(treeNode target) {
treeNode* oneLarger = ...
target.value = oneLarger->value;
}
template <typename T>
class Node {
private:
T data;
Node<T> * next;
public:
Node(T _data, Node<T> * _next): data(_data), next(_next){}
T get_data() const {
return this->data;
}
Node<T> * get_next() const {
return this->next;
}
void set_data(T data) {
this->data = data;
}
void set_next(Node<T> * next) {
this->next = next;
}
};
now I try to invoke the 'set_next()' function on the dereferenced object pointer:
Node<T> new_element(element, NULL);
Node<T> * tmp = this->get_last(); // returns a pointer to the last element
*tmp.set_next(&new_element);
when I try to compile the console prints this errer message:
error: request for member ‘set_next’ in ‘tmp’, which is of pointer
type ‘Node<int>*’ (maybe you meant to use ‘->’ ?)
*tmp.set_next(&new_element);
I don't understand why the compiler wants me to use '->' because '.' is a perfectly fine way to invoke a public member function, right?
However when I put:
Node<T> new_element(element, NULL);
Node<T> * tmp = this->get_last();
*tmp->set_next(&new_element);
I get this:
error: void value not ignored as it ought to be
*tmp->set_next(&new_element);
I don't understand what that means, can someone help me?
Due to operator precedence,
*tmp.set_next(&new_element);
is the same as
*(tmp.set_next(&new_element));
which is clearly not what you want.
You may use
(*tmp).set_next(&new_element);
or
tmp->set_next(&new_element);
tmp->set_next(&new_element);
is the correct usage.
The error message occurs because the * tries to dereference the return value, which is void.
I only want the below function to be called when the template type is a pointer. The code below is a function of a linked list (custom class not anything standard) that is a template of type t. A compilation error is being thrown when the template type is not a pointer, even when the function is not called at all. I need a way to throw an error only if the function is called from non-pointer template type and an error not to occur if it is called from a template type that is a pointer.
virtual void ClearAndDelete()
{
ListNode<t> * ptr = this->FirstNode;
for (; ptr != nullptr; )
{
ListNode<t> * nextptr = ptr->Next;
delete ptr->Item;//ERROR C2541
delete ptr;
ptr = nextptr;
}
this->TotalNodes = 0;
this->FirstNode = nullptr;
this->LastNode = nullptr;
}
The specific error code from Visual Studio 2015 is
Error C2541 'delete': cannot delete objects that are not pointers. This is occurring on a template type that is 'unsigned short' even though none of my code for that template type calls this function. Suggestions would be appreciated.
As requested this is the definition of ListNode
template<typename t> struct ListNode
{
public:
t Item;
ListNode<t> * Next;
ListNode(t what) : Item(what)
{
this->Next = nullptr;
}
ListNode(t what, ListNode<t> * nextnode) : Item(what)
{
this->Next = nextnode;
}
};
If you just want to find out, where your class is erroneously used with a non-pointer template parameter type, you can use static_assert:
template<class t>
class List {
static_assert(!std::is_pointer<t>::value, "Template parameter must be of pointer type");
//other stuff
};
If you want the ClearAndDelete() function to be usable with pointer and non-pointer types, you could e.g. use something like this:
template<class T>
void deleteIfPointer(const T& element) {}
template<class T>
void deleteIfPointer(T* ptr) {
delete ptr;
}
usage:
deleteIfPointer(ptr->Item); //instead of delete ptr->Item
On a side note: Usually containers should not delete objects that their elements point to (If you need this behavior, you might want to use std::unique_ptr instead).
I have one semestral work (own double linked list) and our teacher want this definition of class DoubleList:
template <typename T> //just part of all methods
class DoubleList {
public:
DoubleList(void); //We HAVE TO follow this definitions
void AddFirst(const T &); //const!
T &AccessActual(void);
T RemoveFirst(void);
}
My question is, how can I define a node? AddFirst have const argument and other methods haven't. Data must be set in constructor and then they can't be changed. Is this task so limited or are here other ways to complete the task?
Here is my actual Node:
template <class U>
class Node{
Node<U> * next;
Node<U> * previous;
const U * data;
public:
Node(const U *data){ //
next = NULL;
previous = NULL;
this->data = data;
}
void SetNext(Node<U> *next) {
this->next = next;
}
Node<U> *GetNext(){ return next; }
void SetPrevious(Node<U> *previous) {
this->previous = previous;
}
Node<U> *GetPrevious(){ return previous; }
const U *GetData() { return data; }
};
In containers, it's usually better to have a copy of the data so change const U * data; to U data;
The Node constructor would be easier to use if it had this signature Node(const U& data). No pointers.
The GetData would also have to change. Return a reference. U& GetData().
It is dangerous to hold addresses of data items. If the user of the lists wants that functionality he can use a list that stored pointers (e.g. U=int*)
Your node class seems fine, although i would keep using template argument T instead of U, right now it is confusing.
Your AddFirst() method should simply create a new node and assign the correct next pointer to the new node and the correct prev pointer to the "old" first node and adjust the actual object? what does that refer to?
Your interface of nodes differs from this one returning a reference instead of a pointer. I find it quite strange that the AccessActual can always return an object, while when the list is empty this can be a nullptr??
example implementation:
void AddFirst(const T &)
{
Node<T>* newNode = new Node<T>(T);
Node<T>* current = &AccessActual(); // how can there be an actual when the list can be empty or is that impossible?
{
while( current.GetPrev() != nullptr )
{
current = *current.GetPrev();
}
current.SetPrev(newnode);
newnode->SetNext(current);
}
}
I've got a linked list where I save data, and a pointer to next node, Node<T>* next, like this:
template <class T>
struct Node
{
T data;
Node<T>* next;
};
The thing is I want to put in this a post-increment operator, so it returns the previous value of my node, but increment the reference. So if I do this
Node<int>* someNode = someList.SomeNode();
Node<int>* tmp = someNode++;
tmp would be the original someNode value, but someNode would be someNode->next.
is it possible to put an operator in the struct? I've tried to, and searched how to do it, but as I don't deal with operators I don't know how to do.
You cannot add member function to basic type like pointer.
What are you trying to define is an iterator. Use wrapper class over your node pointer to succeed:
template <class T>
struct NodeIterator
{
NodeIterator(Node<T>* current) : current(current) {}
NodeIterator& operator ++() { current = current->next; return *this; }
NodeIterator operator ++(int) {
NodeIterator retVal = *this;
++(*this);
return retVal;
}
T* operator-> () const { return ¤t->data; }
T& operator * () const { return current->data; }
Node<T>* current;
};
See std::slist<> implementation for references. Look at template<typename _Tp> struct _List_iterator. Reading STL implementation is better than many books.
Usage:
NodeIterator<T> it = &node;
++it;
T& t = *it;
Node<T>& operator++(int) {…}
is the member you want to implement.
For your code to work, you'd need to be able to define operator++ for your pointer class. That's not allowed, though. You're welcome to define some other named function, though. For example:
template <typename Node>
Node goto_next(Node& node) {
Node result = node;
node = node->next;
return result;
}
Then you can use it like this:
Node<int>* tmp = goto_next(someNode);
Another option is to provide a real iterator class instead of just using a pointer:
Node<int>::iterator someNode = someList.begin();
Node<int>::iterator tmp = someNode++;
Make your iterator keep a Node<T>* member, and make the ++ operator update that internal pointer before it returns a copy of the iterator object.
You really don't want to do that. The idea of using ++ on a pointer is dangerously close to the common iterator pattern. You should just go the full distance and make a real iterator class. Think of std::list<T>::iterator.
Iterators are very lightweight wrappers to give a sensible interface to a node pointer, which provides things like operator ++ to move to the next node, and overloads operator -> to provide simple access to the node data. Converting client code from using a pointer to using an iterator is very straight-forward because the syntax is almost identical.