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.
Related
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.
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 the following code snipped, which implements a Binary Search Tree with templates:
#include<iostream>
using namespace std;
template<typename T>
class Node{
public:
T data;
Node<T> *left;
Node<T> *right;
Node<T> *parent;
Node(T input_data=NULL){
data=input_data;
left=NULL;
right=NULL;
parent =NULL;
}
};
template<typename T>
class BinarySearchTree{
private:
long n;
Node<T> *root;
public:
BinarySearchTree(Node<T> *input_root=NULL, long input_size=0){
n=input_size;
root=input_root;
}
void insert(Node<T> *p=root, T data){
Node<T> *par=NULL;
while(p!=NULL){
par=p;
if(data <= p->data)
p=p->left;
else
p=p->right;
}
Node<T> *z=new Node<T>(data);
if(root==NULL){
root=z;
n=1;
return;
}
z->parent=par;
if(data<=par->data)
par->left=z;
else
par->right=z;
n+=1;
}
void inorder(Node<T> *p=root){
if(p){
inorder(p->left);
cout<<p->data<<" ";
inorder(p->right);
}
}
int main(){
BinarySearchTree<int> *t=new BinarySearchTree<int>();
t->insert(5);
t->insert(15);
t->insert(3);
t->insert(14);
t->insert(25);
t->insert(10);
t->inorder();
}
There's a compilation error on line 27, (i.e. Node *root;), and which reads: "Invalid use of non-static data member 'BinarySearchTree::root'". I think it has to do with the default arguments that I've included have in the functions 'insert' and 'inorder', because I don't get the error when I remove the default argument 'root'.
My question is, what is happening and how do I get around it? I would like to preserve the default argument of root if that's possible.
If it matters, I'm using a software called 'Quincy 2005' on Windows 8.1 to compile (for certain reasons).
A default value must be a literal, not a variable name.
Additionally, arguments with default values must come last in the argument list.
Rather use:
void insert(Node<T> *p, T data) { ... }
// overload with only one argument
void insert(T data)
{
insert(root, data)
}
In a line such as
void insert( Node<T>* p = root ,T data ) {...}
there are 2 errors.
Firstly ,you can only use default value for the arguments starting at the last parameter and backwards.
Since you didn't give data a default value ,this is an error (solution reorder parameters ,those without default must come first).
Secondly ,the value root is a member of this and there is no this at the point of declaration.
Solution if you need a default there use nullptr as the default and inside your function test for nullptr and if so use root 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 am confused with what exactly goes wrong in the following demo code. I expected that the next would keep pointing to the next element in the chain until reached end. However, I get EXE_BAD_ADDESS error. I guess I am missing something in the recursive pointer assignment.
template <class T>
struct Node {
Node *left, *right, *parent;
int height;
T value;
// constructor
Node(T val)
: value(val){
height = 0;
left = right = NULL;
}
};
template <class T>
void assignToNext(Node<T> *n, Node<T> *next){
// base case
if (n == NULL)
return;
// else assign to this node and check for next
next = n;
assignToNext(n->left, next);
}
And then in the main:
Node<int> a(1);
a.left = new Node<int>(2);
a.left->left = new Node<int>(3);
a.left->left->left = new Node<int>(4);
a.left->left->left->left = new Node<int>(5);
Node<int> *last = NULL;
assignToNext(&a, last);
std::cout << last->value << std::endl; // I get EXE_BAD_ADDRESS error
Thanks in advance,
Nikhil
void assignToNext(Node<T> *n, Node<T> *next){
-->
void assignToNext(Node<T> *n, Node<T> *&next){ // note the &
Otherwise the original pointer isn't updated and stays NULL.
assignToNext(&a, last);
This code can't modify local variable Node<int> *last's value. You just passed NULL to parameter Node<T> *next. So last's value is still NULL and you got error. If you want modify pointer's value, use double pointer.
Like,
void assignToNext(Node<T> *n, Node<T> **next);
assignToNext(&a, &last);