How to construct an class template with std::allocator construct - c++

How can i construct my class template in my member function newNode (in std=++98) without new operator ?
I tried to put an constructor of Node or the variable key but it doesn't work .
template <class T>
class Node{
public:
Node(){
_left = NULL;
_right = NULL;
_height = 0;
};
Node(const Node &ref);
Node &operator=(const Node &ref);
~Node(){};
T _key;
Node *_left;
Node *_right;
int _height;
};
template <class T, class A = std::allocator<Node<T> > >
class Tree{
public:
[...]
//attribut
Node<T> *head;
A _alloc;
Node<T> *newNode(T key){
Node<T> *node = _alloc.allocate(sizeof(Node<T>));
_alloc.construct(node, ???);
return (node);
}
};
What can i put in my 2nd argument of construct ?

allocate() already calculates the memory required for objects, you shouldn't use sizeof there. Also, don't use construct(), it was removed in C++20. Use placement new instead:
Node<T> *newNode(T key){
Node<T> *node = _alloc.allocate(1); // allocate 1 * sizeof(Node<T>)
new(node) Node<T>(/*arguments to Node<T> constructor, but Node<T> only has default constructor, so nothing goes here*/);
return node;
}
With C++20, you can also use std::construct_at(), which has easier syntax than placement new:
Node<T> *newNode(T key){
Node<T> *node = _alloc.allocate(1); // allocate 1 * sizeof(Node<T>)
node = std::construct_at(node);
return node;
}
To use construct() before C++11, you need to create an object to be copied:
Node<T> *newNode(T key){
Node<T> *node = _alloc.allocate(1); // allocate 1 * sizeof(Node<T>)
_alloc.construct(node, Node<T>());
return node;
}

Related

Copy Constructor Error "Terminate called after throwing an instance of 'int'" [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 10 months ago.
Improve this question
The task was to create a copy constructor for a Forward_list class, and this is the code I have tried. But it keeps showing an error:
terminate called after throwing an instance of 'int'
I have been editing and changing, but I can't seem to get past that error.
class Forward_list
{
public:
class Node
{
public:
// A node will hold data of type T
T data{};
// next will point to the next node in the list
// we initialise next to nullptr
Node* next = nullptr;
// Because we have already intialised the variables
// the default constructor doesn't need to do anything
Node(){}
// if the constructor is called with just one argument.
Node(T input_data, Node* next_node= nullptr)
{
data = input_data;
next = next_node;
}
// Destructor
~Node(){}
};
private:
// private member variables for Forward_list
unsigned size_ = 0;
Node* head_ = nullptr;
public:
Forward_list(const Forward_list<T>& other);
template <typename T>
Forward_list<T>::Forward_list(const Forward_list& other) {
head_ = nullptr;
Node *prev_node = nullptr;
for(Node *other = head_; other != nullptr; other = other->next) {
Node *new_node = new Node;
new_node->data = other->data;
new_node->next = nullptr;
if (!head_)
head_ = new_node;
else
prev_node->next = new_node;
prev_node = new_node;
}
}
Nothing in this code throws an int. So it has to be in code you have not shown. Perhaps in the constructor of T?
Not that it matters, because your copy constructor does not even run its loop at all, since you are looping through the wrong list. You are starting your loop with this->head_ when you need to start it with other.head_ instead.
Also, the Node converting constructor should take its input_data parameter by const reference, and use a member initialization list, to avoid having to default-construct and then assign the data member in separate operations.
Also, the Forward_list copy constructor can be simplified.
Also, make sure you are following the Rule of 3/5/0, if you are not already doing so (you did not show that code).
Try something more like this:
class Forward_list
{
public:
class Node
{
public:
T data;
Node* next;
Node(const T &input_data, Node* next_node = nullptr);
};
Forward_list() = default;
Forward_list(const Forward_list<T>& other);
Forward_list(Forward_list<T>&& other);
~Forward_list();
Forward_list& operator=(Forward_list<T> other);
...
private:
// private member variables for Forward_list
unsigned size_ = 0;
Node* head_ = nullptr;
};
template <typename T>
Forward_list<T>::Node(const T &input_data, Node* next_node)
: data(input_data), next(next_node)
{
}
template <typename T>
Forward_list<T>::Forward_list(const Forward_list& other) {
Node **new_node = &head_;
for(Node *other_node = other.head_; other_node != nullptr; other_node = other_node->next) {
*new_node = new Node(other->data);
++size_;
new_node = &((*new_node)->next);
}
}
template <typename T>
Forward_list<T>::Forward_list(Forward_list&& other) :
head_(std::exchange(other.head_, nullptr)),
size_(std::exchange(other.size_, 0))
{
}
template <typename T>
Forward_list<T>::~Forward_list() {
Node *node = head_;
while (node) {
Node *next = node->next;
delete node;
node = next;
}
}
template <typename T>
Forward_list<T>& Forward_list<T>::operator=(Forward_list other)
{
std::swap(head_, other.head_);
std::swap(size_, other.size_);
return *this;
}

How to create a constructor of linked list for iterator class in c++?

When I try to run this code I get this error :
constructor for 'Linkedlist' must explicitly initialize the member
'point' which does not have a default constructor
Linkedlist::Linkedlist()
class Node {
public:
Node* next;
Node* prev;
Elem elem;
friend class Linkedlist;
Node(): next(NULL), prev(NULL)
{}
Node(Elem elem) : elem(elem)
{}
};
class Iterator {
private:
Node* iter;
//Iterator(Node curr);
public:
friend class Linkedlist;
Iterator(Node* curr) {
iter=curr;
}
};
class Linkedlist {
private:
Node *head;
Node *tail;
int N;
Iterator point;
public:
Iterator point;
Linkedlist();
};
Linkedlist::Linkedlist() {
N = 0;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
point.iter = head;
}
I am not sure how to solve this problem, any help appreciated!
There are a couple of things you could do. You could declare it as a pointer
class Linkedlist { //Missing a c on your class declaration
private:
Node *head;
Node *tail;
int N;
//Iterator point; (You have this declared twice)
public:
Iterator *point;
Linkedlist();//s
In this case you'd need to call the constructor for point in the LinkedList constructor like so.
Linkedlist::Linkedlist() {
N = 0;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
point = new Iterator(head); // Use the existing constructor
}
Alternatively, you could create a default constructor for the Iterator class.
class Iterator {
private:
Node* iter;
public:
friend class Linkedlist;
Iterator() {
iter = 0;
}
Iterator(Node* curr) {
iter=curr;
}
};
Finally, you could use this syntax that instructs the program to allocate point with a null pointer before allocating memory for LinkedList.
Linkedlist::Linkedlist() : point(0) {
N = 0;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
point.iter=head;
}

expected type-specifier error, any ideas as to what I am doing wrong?

I am trying to implement a DEQUE using double linked list.
DEQUE.h
using namespace std;
template <typename T>
class Node{
Node(const T& data):data(data), next(0), prev(0) {}
public:
Node* next;
Node* prev;
T data;
};
template <typename T>
class DEQUE
{
//interface
};
DEQUE.cpp
template <class T>
void DEQUE< T > ::AddFirst(T t){
Node<T>* temp = new Node(t);
if ( counter != 0 ) {
temp->next = head;
temp->prev = 0 ;
head->prev = temp;
head =temp;
counter++;
}
else{
head = temp;
tail = temp;
temp->next = 0;
temp->prev = 0;
counter++;
}
};
I am getting expected type-specifier before 'Node' error on the line
Node<T>* temp = new Node(t);
what am I doing wrong here? Thanks for the help in advance.
You forgot the type when creating an instance of Node:
Node<T>* temp = new Node<T>(t);
^^^ missing.
The type used to create an instance of Node is not automatically assumed to be same as the type used for DEQUE. You have to explicitly specify it.

C++ LinkedList using template

I want to make my own linkedlist implementatin in c++ using templates. However, I run into several compiler errors. Here is the code:
template <class T>
class Node{
T datum;
Node _next = NULL;
public:
Node(T datum)
{
this->datum = datum;
}
void setNext(Node next)
{
_next = next;
}
Node getNext()
{
return _next;
}
T getDatum()
{
return datum;
}
};
template <class T>
class LinkedList{
Node<T> *node;
Node<T> *currPtr;
Node<T> *next_pointer;
int size;
public:
LinkedList(T datum)
{
node = new Node<T>(datum);
currPtr = node; //assignment between two pointers.
size = 1;
}
void add(T datum)
{
Node<T> *temp = new Node<T>(datum);
(*currPtr).setNext((*temp));
currPtr = temp;
size++;
}
T next()
{
next_pointer = node;
T data = (*next_pointer).getDatum();
next_pointer = (*next_pointer).getNext();
return data;
}
int getSize()
{
return size;
}
};
when I try to instantiate this class, I got the following errors:
LinkedList.cpp: In instantiation of `Node<int>':
LinkedList.cpp:35: instantiated from `LinkedList<T>::LinkedList(T) [with T = int]'
LinkedList.cpp:60: instantiated from here
LinkedList.cpp:7: error: `Node<T>::_next' has incomplete type
LinkedList.cpp:5: error: declaration of `class Node<int>'
make[2]: *** [build/Debug/Cygwin-Windows/LinkedList.o] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
I'm using NetBeans IDE. Could anybody give me some suggestion to improve it? Thanks a lot!!
Just like when you do Node<T> *node; in the LinkedList, you need to also do the same in your Node class
template <class T>
class Node{
T datum;
Node<T> *_next;//template parameter
//also, need to make this a pointer and initialized in constructor
public:
//...
void setNext(Node<T> next) //template parameter
{
_next = next;
}
Node<T> getNext() //template parameter
{
return _next;
}
//...
};
Besides the syntax being wrong:
class Node{
T datum;
Node _next = NULL;
//....
you can't have a member of the same type as a member. You can use a pointer though:
template <class T>
class Node{
T datum;
Node<T>* _next;
and set it in the constructor (because =NULL wouldn't be legal there).
Related: Why is a class allowed to have a static member of itself, but not a non-static member?
Your Node class should contain a pointer to the next Node, not a Node directly. Here you've a recursive type which is impossible to handle for the compiler.
Another mistake is that you cannot initialize a member like this. You must do that in the constructor.
So, replace Node _next = NULL; by Node *_next; and initialize the pointer _next to nullptr in your constructor.
It might just be this line:
Node _next = NULL;
You really need that to be a pointer (Node<T>* _next). If a class contained an instance of its own type, then THAT instance would have its own instance of that type and so on ad memorum exhaustum.

C++ new pointer from pointer to pointer?

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);
}
};