a function call changes it's parameters - c++

I have the following code:
#include <iostream>
using namespace std;
template <class T>
class Iterator;
template <class T>
class List;
template <class T>
class List {
public:
struct Node;
Node* first;
friend class Iterator<T>;
List() :
first(NULL) { }
Iterator<T> begin() {
cout << first->data << endl;
return Iterator<T>(*this, first); // <--- problematic call
}
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
};
template <class T>
struct List<T>::Node {
private:
T data;
Node* next;
friend class List<T>;
friend class Iterator<T>;
Node(const T& data, Node* next) :
data(data), next(next) { }
};
template <class T>
class Iterator {
private:
const List<T>* list;
typename List<T>::Node* node;
friend class List<T>;
public:
Iterator(const List<T>& list, typename List<T>::Node* node) {
cout << node->data << endl;
}
};
int main() {
List<int> list;
list.insert(1);
list.begin();
return 0;
}
First I set the node data to "1" (int). Ater that I just pass it to the Iterator constructor, but it changes the value of node->data.
I printed node->data before and after the call:
1
2293232
I guess that 2293232 is an address of something, but I can't find the reason this happens.

When you write
void insert(const T& data) {
Node newNode(data, NULL);
first = &newNode;
}
Then:
You create an object on the stack
Point some (more) persistent pointer to its address
Destruct it as it goes out of scope
So you're left with garbage stuff.

Related

Restruct list iterator after erase

I've created a custom Node, Iterator and List.
I would like to do:
List<int> list;
// push_back objects here...
List<int>::Iterator it = list.begin();
list.erase(it);
++it;
list.erase(it); // error here
So I need to reconstruct the iterator after erasing an element. How do I do that?
Node.h
#pragma once
namespace Util
{
template<typename T>
class Node
{
public:
template<typename T> friend class Iterator;
template<typename T> friend class List;
private:
Node();
Node(T);
~Node();
/* unlink(): takes out this node
and links next and prev to each other
prev <- this -> next
prev <- -> next
this <- this -> this
*/
void unlink();
private:
T value;
Node<T>* next;
Node<T>* prev;
};
template<typename T>
Node<T>::Node() : next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::Node(T t) : value(t), next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::~Node()
{
unlink();
}
template<typename T>
void Node<T>::unlink()
{
next->prev = prev;
prev->next = next;
next = this;
prev = this;
}
}
Iterator.h
#pragma once
#include "Node.h"
namespace Util
{
template<typename T>
class Iterator
{
public:
template<typename T> friend class List;
Iterator& operator++();
T& operator*() const;
bool operator==(const Iterator& rhs) const;
bool operator!=(const Iterator& rhs) const;
private:
Iterator(Node<T>* n);
Node<T>* node;
};
template<typename T>
Iterator<T>::Iterator(Node<T>* n) : node(n)
{
// ...
}
template<typename T>
Iterator<T>& Iterator<T>::operator++()
{
node = node->next;
return *this;
}
template<typename T>
T& Iterator<T>::operator*() const
{
return node->value;
}
template<typename T>
bool Iterator<T>::operator==(const Iterator& rhs) const
{
return node == rhs.node;
}
template<typename T>
bool Iterator<T>::operator!=(const Iterator& rhs) const
{
return node != rhs.node;
}
}
List.h
#pragma once
#include "Iterator.h"
namespace Util
{
template<typename T>
class List
{
public:
typedef Iterator<T> Iterator;
typedef Node<T> Node;
List();
~List();
// Capacity
bool empty() const;
int size() const;
// Modifiers
void push_back(const T&);
void push_front(const T&);
void pop_back();
void pop_front();
Iterator erase(Iterator it);
// Element access
Iterator begin() const;
Iterator end() const;
private:
Node* head;
int list_size;
};
template<typename T>
List<T>::List() : list_size(0)
{
head = new Node();
}
template<typename T>
List<T>::~List()
{
while (!empty()) pop_back();
delete head;
}
template<typename T>
bool List<T>::empty() const
{
return head->next == head;
}
template<typename T>
int List<T>::size() const
{
return list_size;
}
template<typename T>
void List<T>::push_back(const T& t)
{
Node* n = new Node(t);
n->next = head;
n->prev = head->prev;
head->prev->next = n;
head->prev = n;
++list_size;
}
template<typename T>
void List<T>::push_front(const T& t)
{
Node* n = new Node(t);
n->prev = head;
n->next = head->next;
head->next->prev = n;
head->next = n;
++list_size;
}
template<typename T>
void List<T>::pop_back()
{
if (head->prev == head) return;
delete head->prev;
--list_size;
}
template<typename T>
void List<T>::pop_front()
{
if (head->next == head) return;
delete head->next;
--list_size;
}
template<typename T>
typename List<T>::Iterator List<T>::erase(Iterator it)
{
if (it.node == head) return it;
Node* n = it.node->next;
delete it.node;
--list_size;
return Iterator(n);
}
template<typename T>
typename List<T>::Iterator List<T>::begin() const
{
return Iterator(head->next);
}
template<typename T>
typename List<T>::Iterator List<T>::end() const
{
return Iterator(head);
}
}
Edit: after updating the code based on the comments I received. Going through the list and erasing, only erases every other element; since the loop is incrementing the iterator and erase makes the iterator's current object iterator's next object. Is this how it is in the standard as well?
for (Util::List<int>::Iterator it = list.begin(); it != list.end(); ++it)
{
it = list.erase(it);
}
Old list: 0 1 2 3 4 5 6 7 8 9
After erasing: 1 3 5 7 9
Please do not complain about rule of five and things unrelated to the question. I haven't gotten to every part yet. My justification of making an edit over posting a new question is that the edit is still about how to reconstruct the iterator correctly after erase.
As some people already mentioned, erase typically returns a new, valid iterator, if that is possible/feasible for the container.
You can define the semantics as you would like, but typically you would erase the element by pointing prev->next to next and next->prev to prev, then deallocate the node, and return an iterator to next. You could also return an iterator to prev, but that results in several counter-intuitive behaviors, such as having to advance the iterator if you are doing an operation on some sort of range. Returning an iterator to next, just lets you delete ranges with while(foo(it)) it = c.erase(it);
In that case you of course don't increment the iterator anymore, unless you wan t to skip every other element.

My linkedlist print function goes into infinite loop

linkedlist.h
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include <iostream>
template <typename T>
class list{
public:
list();
class node;
typedef T value_type;
typedef T& reference;
typedef node node_type;
typedef node_type* node_pointer;
list& push_back(value_type);
value_type pop_front();
node_pointer begin() const;
private:
node_pointer head, tail;
};
template <typename T>
class list<T>::node{
public:
node(value_type value = 0);
void setData(value_type);
value_type getData() const;
void setNext(node_pointer);
node_pointer getNext() const;
private:
value_type data;
node_pointer ptr_next;
};
template <typename T>
inline list<T>::node::node(value_type value) : data(value), ptr_next(nullptr){
}
template <typename T>
void list<T>::node::setData(value_type value){
this->data = value;
}
template <typename T>
typename list<T>::value_type list<T>::node::getData() const{
return this->data;
}
template <typename T>
void list<T>::node::setNext(node_pointer ptr){
this->ptr_next = ptr;
}
template <typename T>
typename list<T>::node_pointer list<T>::node::getNext() const{
return this->ptr_next;
}
template <typename T>
list<T>::list() : head(nullptr), tail(nullptr){
}
template <typename T>
list<T>& list<T>::push_back(value_type value){
node_pointer item = new node_type(value);
if(this->tail) this->tail->setNext(item);
this->tail = item;
if(!this->head) this->head = this->tail;
return *this;
}
template <typename T>
typename list<T>::value_type list<T>::pop_front(){
if(this->head){
node_pointer item = this->head;
value_type value = this->head->getData();
this->head = this->head->getNext();
delete item;
return value;
}
return 0;
}
template <typename T>
typename list<T>::node_pointer list<T>::begin() const{
return this->head;
}
template <typename T>
std::ostream & operator<<(std::ostream &stream, list<T> &obj){
typename list<T>::node_pointer ptr = obj.begin();
while(ptr->getNext() != nullptr){
stream << ptr->getData() << " ";
ptr->setNext(ptr->getNext());
}
return stream;
}
#endif /* LINKEDLIST_H_ */
main.cpp
#include <iostream>
#include "LinkedList.h"
using std::cout;
using std::endl;
int main (int argc, char ** argv){
list<int> mylist;
mylist.push_back(5).push_back(1);
cout << mylist;
return 0;
}
I just wanted to create a print function which overloads operator<<. whatever i did, i couldn't find the solution. What is the wrong with this overloaded operator<< function? And how can i clean garbage if program throws error. How destructor function should be?
template <typename T>
std::ostream & operator<<(std::ostream &stream, list<T> &obj){
typename list<T>::node_pointer ptr = obj.begin();
while(ptr != nullptr){
stream << ptr->getData() << " ";
ptr = ptr->getNext();
}
return stream;
}
i realized that i made a logical mistake during the print function. But i still wonder how to collect garbage?

Template Class data type

I've created this pretty simple dynamic list which is implemented with a template class:
Node.h
template <class T> class Node
{
public:
typedef T data_type;
typedef T& reference_type;
void setData(data_type);
void setNextNull();
void setNext(Node*);
reference_type getData();
Node* getNext();
private:
data_type data;
Node* next;
};
template <class T> void Node<T>::setData(data_type _data)
{
data=_data;
}
template <class T> void Node<T>::setNextNull()
{
next=NULL;
}
template <class T> void Node<T>::setNext(Node* _next)
{
next=_next;
}
template <class T> typename Node<T>::reference_type Node<T>::getData()
{
return data;
}
template <class T> typename Node<T>::Node* Node<T>::getNext()
{
return next;
}
List.h
#ifndef LIST_H
#define LIST_H
#include <Node.h>
template <class T> class List
{
public:
typedef Node<T> node_type;
typedef node_type* node_pointer;
typedef T data_type;
typedef T& reference_type;
List();
void push_back(data_type);
reference_type at(int);
void clear();
void swap(int,int);
int size();
private:
int list_size = 0;
node_pointer head, tail;
};
template <class T> List<T>::List()
{
head=NULL;
}
template <class T> void List<T>::push_back(data_type data)
{
if(head == NULL) {
head = new node_type;
head->setData(data);
tail = head;
} else {
node_pointer temp = new node_type;
temp->setData(data);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
list_size++;
}
template <class T> typename List<T>::reference_type List<T>::at(int x)
{
node_pointer pointer=head;
for(int i=0; i<x; i++)
pointer=pointer->getNext();
return pointer->getData();
}
template <class T> void List<T>::clear()
{
node_pointer pointer = head;
for(int i=0; i<list_size; i++) {
node_pointer temp = pointer;
pointer=pointer->getNext();
delete(temp);
}
head=NULL;
list_size=0;
}
template <class T> void List<T>::swap(int x, int y)
{
data_type buffer=at(x);
at(x)=at(y);
at(y)=buffer;
}
template <class T> int List<T>::size()
{
return list_size;
}
#endif // LIST_H
The list works perfectly with any form of data type, except when i use a class with a parameter inside it's constructor, then I get this error:
include/Node.h error: no matching function for call to ‘Player::Player()’
What am I doing wrong??
UPDATE 1
I've added a simple constructor as suggested but I get the same error
template <class T> Node<T>::Node(data_type _data)
{
data=_data;
}
You probably haven't defined a default constructor for your Player class. Just insert an empty constructor
Player() {}
And your problem will likely to be solved.
When you write a template method and use it in the main function like this:
Node<Player>
The compiler automatically calls the constructor of the Player class.
If you didn't define any constructors in Player, the compiler will use default constructor. However, any constructor you defined will hide the default one and force you to use this one.
For instance, a constructor like
Player(string, int, int)
Prevents you to create an object like this:
Player *p = new Player();
However, if you haven't written the constructor, the piece of code above would've worked just fine.
That's why your template needs a default constructor, iff you defined a parameterized constructor.
Your class Node should have a constructor which take a T so you can construct your T by copy instead of requiring to have a default constructor and copy.
your Node class would be something like:
template <class T>
class Node
{
public:
Node(const T& data) : data(data), next(0) {}
void setNextNull();
void setNext(Node*);
const T& getData() const { return data; }
T& getData() { return data; }
Node* getNext();
private:
T data;
Node* next;
};
and so you transform
head = new node_type;
head->setData(data);
by
head = new node_type(data);

Template function with template parameter

I want to create a factory, that returns AVLNode, if BinaryTree is AVLTree, and Node if the tree is not AVL. I have following code:
#include "BinaryTree.h"
#include "AVLTree.h"
class NodeFactory {
public :
template <class T>
static Node<T>* getNode(BinaryTree<T>* tree);
};
template <class T>
Node<T>* NodeFactory::getNode(BinaryTree<T>* tree) {
if (tree->isAVL()) {
return new AVLNode<T>();
} else {
return new Node<T>();
}
}
UPD: (this is BinaryTree.h)
template <class T> class Node;
template <class T> class BinaryTree {
public:
BinaryTree() {
_isAVL = false;
root = new Node<T>();
}
bool isAVL() {
return _isAVL;
}
private:
T elem;
Node<T>* root;
bool _isAVL;
};
template <class T> class Node {
public:
Node() {
left = NULL;
right = NULL;
}
T get() {
return elem;
}
void setRight(const T elem) {
right = new Node<T>();
right->set(elem);
}
void setLeft(const T elem) {
left = new Node<T>();
left->set(elem);
}
private:
T elem;
Node* left;
Node* right;
};
I removed almost all methods to make code more readable.
Now i have this error during compilation: "expected initializer before '<' token". Also Qt do not highlights in Node, but highlights in BinaryTree
It's a syntax error. You need
template <class T> // or <typename T>
Node<T>* NodeFactory::getNode(BinaryTree<T>* tree) {

Template LinkedList class with nested class

I'm trying to implement a linked list with a template class LList and Nested Iterator and Node classes. Here's the code:
template <typename T1>
class LList
{
public:
class Iterator
{
public:
Iterator();
T1 get() const;
void next();
void previous();
bool equals(Iterator iter) const;
private:
Node* position;
LList* container;
};
LList();
~LList();
void pushBack(T1 data);
Iterator begin();
Iterator end();
void insert (Iterator iter, T1 data);
Iterator erase(Iterator Iter);
private:
class Node
{
public:
Node(T1 data);
private:
T1 data;
Node* ptr_next;
Node* ptr_prev;
};
Node* ptr_first;
Node* ptr_last;
};
template <typename T1>
LList<T1>::Node::Node(T1 data)
{
this->data = data;
ptr_next = 0;
ptr_prev =0;
}
template <typename T1>
LList<T1>::Iterator::Iterator()
{
position = 0;
container = 0;
}
template <typename T1>
T1 LList<T1>::Iterator::get() const
{
return position->data;
}
template <typename T1>
void LList<T1>::Iterator::next()
{
if(position == container->ptr_last)
{
position = container->ptr_first;
}
else
{
position = position->ptr_next;
}
}
template <typename T1>
void LList<T1>::Iterator::previous()
{
if(!position)
{
position = container->ptr_last;
}
else
{
position = position->ptr_prev;
}
}
template <typename T1>
bool LList<T1>::Iterator::equals(Iterator iter) const
{
return position == iter.position;
}
template <typename T1>
LList<T1>::LList()
{
ptr_first = 0;
ptr_last = 0;
}
template <typename T1>
LList<T1>::~LList()
{
while (ptr_first)
{
Node* tmp = ptr_first;
ptr_first = ptr_first->ptr_next;
delete tmp;
tmp = 0;
}
}
template <typename T1>
void LList<T1>::pushBack(T1 data)
{
Node* new_node = new Node(data);
if(ptr_first==0)
{
ptr_first = new_node;
ptr_last = new_node;
}
else
{
ptr_last->ptr_next = new_node;
new_node->ptr_prev = ptr_last;
ptr_last = new_node;
}
}
template <typename T1>
Iterator LList<T1>::begin()
{
Iterator iter;
iter.positon = ptr_first;
iter.container = this;
return iter;
}
template <typename T1>
Iterator LList<T2>::end()
{
Iterator iter;
iter.position = ptr_last;
iter.container = this;
return iter;
}
template <typename T1>
void LList<T1>::insert(Iterator iter, T1 data)
{
if (iter.position == 0)
{
pushBack(data);
return;
}
Node* before;
Node* after;
after = iter.position;
before = iter.position->ptr_prev;
Node* new_node = new Node(data);
after->ptr_prev = new_node;
if (before == 0) ptr_first = new_node;
else before->ptr_next = new_node;
new_node->ptr_prev = before;
new_node->ptr_next = after;
}
template <typename T1>
Iterator LList<T1>::erase(Iterator iter)
{
Node* after = iter.position->ptr_next;
Node* before = iter.position->ptr_prev;
Node* remove = iter.position;
if (remove == ptr_first) ptr_first = after;
else before->ptr_next = after;
if (remove == ptr_last) ptr_last = before;
else after->ptr_prev = before;
delete remove;
remove = 0;
}
I've seen how do it without nested classes but I need to do it with a nested class.
Any help on why it doesn't compile will help :) Thanks.
Well, Iterator is the name of a nested class, so when you use it in the definition of a member function of your LList class template as the return type, you have to fully qualify it (and add the typename disambiguator to tell the compiler that what follows the :: shall be parsed as the name of a type).
For instance:
template <typename T1>
typename LList<T1>::Iterator LList<T1>::erase(Iterator iter)
// ^^^^^^^^^^^^^^^^^^^^
There are several instances of this error, so you will have to fix all of them.
You are also referring to class Node before its definition appears inside LList. Therefore, you should have a forward declaration for it:
template <typename T1>
class LList
{
class Node;
// ^^^^^^^^^^^
// Forward declaration for Node
public:
// ...
class Iterator
{
// ...
Node* position; // <== Now this is OK because of the forward declaration
// ...
};
There are different error :
The first is that you use Node into the Iterator class, but you need to declare Node before it :
template <typename T1>
class LList
{
private:
class Node
{
public:
Node(T1 data);
private:
T1 data;
Node* ptr_next;
Node* ptr_prev;
};
Node* ptr_first;
Node* ptr_last;
public:
LList();
~LList();
void pushBack(T1 data);
class Iterator
{
public:
Iterator();
T1 get() const;
void next();
void previous();
bool equals(Iterator iter) const;
private:
Node* position;
LList* container;
};
Iterator begin();
Iterator end();
void insert (Iterator iter, T1 data);
Iterator erase(Iterator Iter);
};
That is the first thing.
The second is that Iterator is a nested type, so you need to be more specific when you return un object of this type :
template <typename T1>
typename LList<T1>::Iterator LList<T1>::begin()
And the last error is :
template <typename T1>
Iterator LList<T2>::end()
Here is the correct lign :
template <typename T1>
typename LList<T1>::Iterator LList<T1>::end()
// ^^^^^^^^^^^^^^^^^ ^^