I'm trying to copy a list into another list.
I have this:
template< typename T > class List {
class Node {
public:
T element;
Node *next;
Node( T a_element, Node * a_suivant = nullptr );
virtual ~Node( void );
};
int _taille;
Node * _first;
Node * _last;
public:
List( void );
virtual ~List( void );
int taille( void );
bool empty( void );
I'm trying to create a function that copies a list (using this) into another list and empty the list in argument. I tried to start with emptying the list first to see if it works but I always get segmentation error.
void copyEmpty( List< T > & a_List ){
Node *c = a_List._last;
while(c!=NULL){
Node *t = c->next;
delete c;
c = t;
if(c==a_List._last) c = NULL;
}
a_List._last = NULL;
}
How can I implement the function using next, _last, _first of the list in use (this) and the list in argument (a_List)?
Above of all, it seems you are a C programmer...
Don't use ( void ) in C++!
Use nullptr instead of NULL! (This might become important for overloaded functions taking pointers if you want to make use of std::nullptr_t, the null pointer type, which is defined as decltype(nullptr))
Use, like #david-c-rankin mentioned, a move constructor, or move operator = for your purpose to be compliant with standard design in C++. At least one of them will also work in your template context you mentioned in a comment.
Now coming to the problem: I don't claim that this is a solution since I'm not sure if a got your question right.
template <typename T>
class List {
class Node {
public:
T element;
Node* next;
Node( const T& a_element, Node* a_suivant = nullptr );
virtual ~Node();
};
int _taille;
Node* _first;
Node* _last;
public:
List();
virtual ~List();
int taille();
bool empty();
};
template <class T>
void copyEmpty( List< T > & a_List ){
for(auto pNode = a_List._first; pNode != a_List._last;){
Node* const pNext{ pNode->next };
delete pNode;
pNode = pNext;
}
delete a_List._last;
a_List._last = nullptr;
a_List._first = nullptr;
}
For now I kept your function name. There is still the need of tackling the privateness of _last etc.
I think in your solution you skip deleting the last one.
Maybe you may add a clear specification what _first, _last and your function are / do respectively.
Related
I am trying to implement two member functions, i.e., push_front and the destructor. I have written the code of the push_front function. But I seem, I am doing wrong anywhere. How can I fix this issue? How can I insert a node in front of Linked-List properly?
template <typename T>
class Node {
public:
Node():next_p_{nullptr} {}
Node(T v, Node* n):data_{v}, next_p_{n} {}
~Node() {};
void setData( T &v ) { data_ = v; }
const T &getData() const { return data_; }
void setNext( Node *n ) { next_p_ = n; }
Node *getNext() const { return next_p_; }
private:
T data_;
Node *next_p_;
};
template <typename T>
class LinkedList {
private:
Node<T> *head_ptr_;
public:
LinkedList():head_ptr_{nullptr} {}
~LinkedList() {
}
// Insert at the front of the linked list (UPDATED)
void push_front( T v ){
Node *new_node = new Node;
new_node->setNext(*head_ptr_) = v;
new_node->next_p_ = this->head_ptr_;
this->head_ptr_ = new_node;
}
};
The first Node constructor takes the value and next pointer, use that to create the new node in one step.
You shouldn't dereference head_ptr_ when using it as the next pointer. It's already a Node*, which is the correct type for head_ptr_.
void push_front( T v ){
Node *new_node = new Node(v, head_ptr_);
this->head_ptr_ = new_node;
}
I would also recommend not dealing with manual memory management and instead use smart pointers to simplify your life a bit.
Using std::unique_ptr you wont have to deal with reclaiming the memory you allocated from the free store.
One caveat to this approach is you lose your ability to copy the List but usually that's what you want anyway.
template<typename T>
class List {
struct Node {
Node( T value ) noexcept
: data{ std::move_if_noexcept( value ) }
{ }
T data;
std::unique_ptr<Node> next{ nullptr };
};
public:
auto push_front( T value ) -> void {
auto node{ std::make_unique<Node>( std::move_if_noexcept( value ) ) };
std::swap( node->next, head_ );
std::swap( head_, node );
}
~List()
{
while (head_) {
std::unique_ptr<Node> tmp(std::move(head_));
head_ = std::move(tmp->next);
}
}
private:
std::unique_ptr<Node> head_{ nullptr };
};
As far as I can understand, linked list can only implemented with an outsider class. Because a class can't have a member varable of it's own type and a node list need that type. The problem is, if the link is intented to be used by a specific class. If, the link class created outside, it will be available to be created as a standalone object.
It's okay if the link class/struct is a pure link object because it can be used for linking another object type. But, in case I need a link that has a functionallity that only related to a certain object, the public availability of it will be pointless. And I think it's better to be created as a private.
Let's take a look at this declaration:
#include <unordered_map>
using namespace std;
template<class T>
class Node
{
public:
Node();
Node(const T& item, Node<T>* ptrnext = NULL);
T data;
// access to the next node
Node<T>* NextNode();
// list modification methods
void InsertAfter(Node<T>* p);
Node<T>* DeleteAfter();
Node<T> * GetNode(const T& item, Node<T>* nextptr = NULL);
private:
Node<T> * next;
unordered_map<string, T*> nodeList;
};
The unordred_map<string,T*> member can only have meaning with a certain object. So, it will be pointless for Node class to be available outside.
Is it possible? Or maybe is it a bad idea to add a non-generic funtionallity for link class?
class A {
A* m_pnext = nullptr;
public:
inline A* next() { return m_pnext; }
inline void set_next(A*ptr) { m_pnext = ptr; }
}
template <class type>
class LinkedList {
type *m_pfirst = nullptr;
public:
void add(type * ptr) {
if ( nullptr == m_pfirst ) {
m_pfirst = ptr;
} else {
type * n = m_pfirst, p = m_pfirst->next;
while (nullptr != p) {
n = p;
p = n->next();
}
n->set_next(ptr);
}
}
};
Plenty of room for improvement, of course. I'll let you exercise your mind.
I am very new to C++ templates. I am currently working on a project where I need to implement a Doubly Linked List using a template. Here is currently what I have so far:
template<class ItemType>
class SortedList
{
public:
SortedList();
~SortedList();
bool Insert (ItemType toAdd);
bool Delete (ItemType toDelete);
void Print();
private:
SortedList ( const SortedList & copyFrom );
SortedList & operator= ( const SortedList & assignFrom );
struct Node
{
Node ( ItemType item, Node * p = NULL, Node * n = NULL )
{ data = item; prev = p; next = n; }
ItemType data;
Node * prev, * next;
};
Node * list;
};
template<class ItemType>
SortedList<ItemType>::SortedList()
{
list == NULL;
}
template<class ItemType>
SortedList<ItemType>::~SortedList()
{
Node * curr = list;
while ( curr != NULL )
{
Node * tempNext = curr->next;
delete current;
current = tempNext;
}
}
However, in my destructor for example, why can't I access the node elements? The code that is inside that method right now compiled, but does not throw errors. However if I try to use -> on curr, next or prev do not appear. Why do I not have access to these? I feel like I am missing something very obvious here to get started.
Also, how can I initialize list == NULL in the function head, instead of doing it outside of the class?
Don't know why it compiles, but you are using
delete current;
current = tempNext;
Instead of:
delete curr;
curr = tempNext;
Use inline initializer syntax:
class SortedList
{
public:
SortedList()
:
list(nullptr)
{ }
Use the same syntax to initialize Node (it's more optimal)
Suppose I have the following definition of List and Node:
template <class T>
class List {
public:
class Iterator;
class ConstIterator;
//Constructors and Destructors.
List() : head(NULL), tail(NULL), size(0) {}
List(const List& list);
~List();
//Methods
Iterator begin();
ConstIterator begin() const;
Iterator end();
ConstIterator end() const;
void insert(const T& data);
void insert(const T& data, const Iterator& iterator);
void remove(const Iterator& iterator);
int getSize() const;
Iterator find(const T& item);
ConstIterator find(const T& item) const;
void sort();
//Operators
List operator = (const List& list);
private:
class Node;
Node* head;
Node* tail;
int size;
};
template <class T>
class List<T>::Node
{
public:
//Constructors and destructors
Node(const T& _data, const Node* _next) : data(_data), next(_next) {}
~Node(); //Destructor
//Methods
//Operators
Node operator = (const Node& node);
private:
T data;
Node* next;
};
I'm writing a function to insert data into a list like this:
template<class T>
void List<T>::insert(const T& data)
{
Node newNode = new Node(data, NULL);
if (head == NULL)
{
head = &newNode;
tail = &newNode;
}
else
{
(*tail)->next = &newNode;
tail = &newNode;
}
size++;
}
However what I find strange is that if I swap (*tail)->next = &newNode; to (*tail).next = &newNode; it still compiles. Why, and what is the correct way of doing it?
The definitions of your classes can be (for the purposes of this question) simplified into:
class List {
...
private:
Node* head;
Node* tail;
};
class Node {
...
private:
Node* next;
};
Now in your List::insert method:
Node newNode = new Node(data, NULL);
(*tail)->next = &newNode;
...when you use new expression, the result will be pointer to the newly allocated memory.
What you should do is:
Node* newNode = new Node(data, NULL);
tail->next = newNode; // <-- equivalent to (*tail).next = newNode;
Using Node->tail is short form of writing (*Node).tail. Both forms are valid. Strangeus is the fact that you say that (*Node)->tail compiles. To this happens, Node must be defined as a double pointer, i.e.:
Node **tail;
But your code has some others bugs in. In this line:
Node newNode = new Node(data, NULL);
you are define a local object and assing a dynamic memory to it. The correct way is:
Node *newNode = new Node(data, NULL); // defining it as a pointer
and instead of assing as:
head = &newNode;
do:
head = newNode;
As a final note, consider using smart pointer instead of raw pointer. The former is safer than the last
The -> operator will automatically derefference a pointer for you then call the method to the right. So:
tail->next
would also work but
tail.next
wouldn't because tail is a pointer. To use the . operator you have to defrence the pointer first as in
(*tail).next
(*tail)
turns your pointer into an object. At that point you can use either -> or .
A . will not work on a pointer but -> will.
Generally, just for easy of typing I use -> because it is shorter then using (*) to turn a pointer into an object just so I can use a dot but they are equivalent operations.
You have noticed that (*tail)->next = &newNode and (*tail).next = &newNode both compile, which strikes you as odd.
But somehow you might also have noticed that this line also compiles!
Node newNode = new Node(data, NULL);
That is the thing that you should give you pause.
You are inside of a template here. Lots of things "compile".
Did you try instantiating the template?
ADDENDUM:
Here just to show you how crazy things can be, check out this program:
#include <iostream>
using namespace std;
template <class T>
class C {
void f();
};
template <class T>
void C<T>::f() {
int x = new int;
}
int main() {
std::cout << "Hello, world\n";
}
Now check this out:
$ g++ template-example.cpp && ./a.out
Hello, world
But now notice
#include <iostream>
using namespace std;
int main() {
int x = new int;
std::cout << "Hello, world\n";
}
which yields:
$ g++ hello.cpp
hello.cpp: In function ‘int main()’:
hello.cpp:4: error: invalid conversion from ‘int*’ to ‘int’
TL;DR: WHEN YOU ARE IN A TEMPLATE, THINGS THAT SHOULD NOT COMPILE SOMETIMES "DO"! (They're not really compiling -- YET!)
I have a template linkedList that I would like to dynamically create "head" pointers for...
I seem unable to get any syntax to work.. my best guess is:
linkedList<int>** ptr;
ptr = new (linkedList<int>*)[1];
But it doesn't work. I'm fairly new to C++ so any help is appreciated! Thanks!
To get a pointer, do:
T* ptr = new T;
where T is your type.
For a pointer-to-pointer, do:
T** ptrptr = new T*;
allocating the space for one pointer, which still needs to be filled like the first method:
*ptrptr = new T;
Now you got a valid pointer-to-pointer.
Is there some reason you are not using std::list? (or std::forward_list)
Check out the header files for std::list, or your nearest C++ book, or in fact
cppreference.com
Your linked list class template should have a function to return the head of the list. Look at std::list::begin() in your compiler's c++ library. The std::list::iterator type is a pointer to whatever goes in the list. (ie T*)
Though I'm not sure pointer array is really needed for your linked
list, as for just new construct, the following form will be compiled.
ptr = new (linkedList<int>*[1]);
EDIT:
This allocates pointer array:
linkedList<int>** ptr = new (linkedList<int>*[1]);
This allocates array:
linkedList<int>* ptr = new linkedList<int>[1];
This allocates one element:
linkedList<int>* ptr = new linkedList<int>;
Normally the head of a linked list would look something like:
node<int> *head = NULL;
When you want to create and insert a node, you'd use something like:
insert(node<int> *&list, int value) {
// insert new node containing `value` at head of `list`.
node<int> *temp = new node(value);
temp->next = list;
list=temp;
}
You could use this something like:
node<int> *list = NULL;
for (int i=0; i<10; i++)
insert(list, i);
Of course, unless this is for homework (or something on that order), you should stop working on this immediately, and just std::list (or boost::slist, if you want a singly-linked list).
Edit: I'm adding more detail mentioned by the OP in comment. For the moment, the avl_tree::insert does not attempt to maintain balance. It's just a plain-jane un-balanced insert, but it should be adequate to demonstrate what we care about at the moment.
template <class T>
struct linked_list {
node *head;
void insert(T v) {
node<T> *n = new node(v, head);
head = n;
}
linked_list() : head(NULL) {}
template <class T>
struct node {
node *next;
T data;
node(T const &v, node *n=NULL) : data(v), next(n) {}
};
};
template <class keyType, class dataType>
class avl_tree {
struct node {
node *left, *right;
char balance;
keyType key;
dataType data;
node(keyType const &k, dataType const &d)
: left(NULL), right(NULL), balance(0), key(k), data(d)
{ }
bool operator<(node const &other) {
return key < other.key;
}
} *root;
bool insert(node const *new_node, node *&tree) {
if (tree == NULL) {
tree = new_node;
return true;
}
else if (*new_node < *tree)
return insert(new_node, tree->left);
else if (*new_node > *tree)
return insert(new_node, tree->right);
else // new_node == tree
return false; // couldn't insert -- already present.
}
public:
avl_tree() : root(NULL) {}
void insert(keyType const &key, dataType const &data) {
node *temp = new node(key, data);
insert(temp, root);
}
};