I have a linked list program,in which I see a lot of -> operators, but I don't know what they do.I searched about them here and there but all I found was that that is a point to member operator and that it does something ( I didn't completely understand what and why ).Here is a code snippet from the linked list, can you explain to me how this operator works?
#include <iostream>
using namespace std;
template<class T>
class List{
struct Element{
T data_;
Element* next_;
Element* prev_;
Element(T val)
:data_(val),
next_(NULL),
prev_(NULL)
{}
};
Element* head_;
So this is the structure I am using and below is a simple push_back function.
void push_back(T val){
Element* newElement = new Element(val);
Element* back = head_->prev_;
back->next_ = newElement;
newElement->prev_ = back;
newElement->next_ = head_;
head_->next_ = newElement;
}
int main(){
List<int> l;
l.push_back(40);
return 0;
}
Examples would be greatly appreciated.
By default, the -> operator is shorthand for dereferencing the pointer and accessing a member.
The C
For example, given the declaration Element* back, then back->next is equivalent to (*back).next.
EDIT:
From Kernighan and Ritchie's "The C Programming Language":
Pointers to structures are so frequently used that an alternative notation is provided as a shorthand. If p is
a pointer to a structure, then
p->member-of-structure
refers to the particular member.
-> usually Just works like this
foo->bar() ====> (*foo).bar()
This is all it does in your example.
However it can be overloaded per class so you can use it on things like shared_ptr. The only restriction is that you can only overload it to return a different pointer to dereference. Eg
class Foo {
int* super_special_ptr;
public:
int* operator->(){ return super_special_ptr; }
};
Related
I was trying to implement generic linked list of objects in C++. But when I fetch the same object twice it gives me different results. I feel it is due to misuse of pointers. Please help me debug.
Here is the Node implementation. I have used pointers for templates since linked list shall contain user defined objects.
template <class T> class Node{
private:
T* value;
Node<T>* next;
public:
Node(T* v){value = v; next = NULL;}
Node(T* v, Node<T>* n){value = v; next = n;}
T* getElement(){return value;}
Node<T>* getNext(){return next;}
};
Here is the implementation for generic linked list.
template <class T> class LinkedList{
public:
Node<T>* head = NULL;
LinkedList(){}
LinkedList(T* value){
Node<T> node(value);
head = &node;
}
Node<T>* getHead(){
return head;
}
void add(T* value){
Node<T> node(value,head);
head = &node;
}
};
Main function:
When I call head of linked list, it gives me 2 different answers. In this code, Complex is a simple class to hold complex objects.
int main(){
Complex c1(1,2); Complex c2(3,4); Complex c3(5,6);
LinkedList<Complex> list(&c1);
list.add(&c2);
cout<<list.head->getElement()->i<<" "<<list.getHead()->getElement()->j<<endl;
cout<<list.head->getElement()->i<<" "<<list.getHead()->getElement()->j<<endl;
return 0;
}
Thanks in advance!!
In LinkedList(T* value) and void add(T* value), you are taking the address of a temporary with head = &node;. As soon as you are out of the scope of that function, head becomes a dangling pointer.
You need to create a new node on the heap so that its lifetime will extend beyond the scope of that function.
Node<T> node = new Node<T>(value);
Don't forget to delete all the nodes you have created in the destructor to avoid memory leaks, or even better, switch to smart pointers instead of raw pointers so the cleanup is done for you.
I'm trying to give my generic list class a reverse function. For some reason, my algorithm ain't workin' when I test it. I thought it made sense: swap the pointers to the first and last nodes of the list, then go through the list and for each node swap its pointers to the previous and next node.
Go easy on me, guys. I'm trying to get some practice with generic programming. Teach me the ways of a C++ purist.
Here's the swap function:
template <class T> void swap(T* a, T* b) {
T* tempPtr = a;
a = b;
b = tempPtr;
}
Here's the reverse function:
template <class T> void List<T>::reverse() {
if (size > 1) {
swap(firstNodePtr, lastNodePtr);
node* curNodePtr = firstNodePtr;
while (curNodePtr != NULL) {
swap(curNodePtr->prevNodePtr, curNodePtr->nextNodePtr);
curNodePtr = curNodePtr->nextNodePtr;
}
}
}
Here's the class, its members and prototypes for functions:
template <class T> class List {
public:
List();
~List();
void push_back(T);
void push_front(T);
T get_at(unsigned);
unsigned get_size();
void reverse();
private:
struct node {
T val;
node* prevNodePtr;
node* nextNodePtr;
};
node* firstNodePtr;
node* lastNodePtr;
unsigned size;
};
Your swap<T> function does not work: it exchanges pointers, which are copied by value into local variables of your function, which has no effect in the caller.
Dropping your own swap and replacing it with std::swap will fix this problem.
Since you pass the two pointers by value, the changes to a and b don't propagate out of the swap() function, making it a no-op.
One way to fix it is by passing the pointers by reference:
template <class T> void swap(T*& a, T*& b) {
Alternatively (and preferably) just use std::swap() instead of your own function.
If you exposed your node structure (or at least a bidirectional iterator type for your list), you could avoid the whole issue and just use std::reverse.
List<int> someList;
// fill with data
std::reverse(someList.begin(), someList.end()); // where begin returns a bidirectional iterator for the head, and end returns a bidirectional iterator for 1 element beyond the tail
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);
}
}
Is it possible to change the address of my current struct using the -- or ++ operator, i.e.:
mystruct* test = existing_mystruct;
test++ // instead of using: test = test->next_p;
I was trying to use this, but it seems to be const and gives me an Error: assignment to this (anachronism):
struct mystruct {
mystruct* next_p;
mystruct* prev_p;
void operatorplusplus () { this = next_p; }
void operatorminusminus() { this = prev_p; }
};
Objects have a constant address in memory while they exist.
You may copy them to a new address, however.
What you try to do is advance in a linked list. And it may be done with those operators if you overload them. But you will need to define that in a special handle class to wrap over the list nodes.
EDIT
The code for what I describe will look somewhat like this:
class mylist
{
struct mynode
{
//data
mynode* next;
mynode* prev;
} *curr;
public:
mylist& operator++() {curr = curr->next; return *this;}
};
Naturally you'd wanna do boundry checks and such, but that's the general idea.
No. this pointer is of type mystruct * const, which means its address is unchangeable.
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.