I am trying to create a simple stack using templated classes. There seems to be an issue when one class calls the constructor of the other class.
#include <iostream>
#include <vector>
int g_MaxSize = 100;
template <class T>
class Stack;
template <class D>
class Node
{
private:
D data;
public:
Node(D value): data(value)
{
}
template <class T>
friend class Stack;
};
template <class T>
class Stack
{
private:
std::vector<Node<T>> stack;
int top;
public:
Stack(): stack(g_MaxSize), top(0)
{
}
void push(T val)
{
// make sure stack isnt full
stack[top++]= Node<T>(val);
}
Node<T> pop()
{
return stack[top--];
}
Node<T> peek()
{
return stack[top];
}
};
int main() {
Node<int> testNode(1) // *this works*
Stack<int> myStack;
myStack.push(3);
return 0;
}
The error is " No matching constructor for initialization of 'Node' ". As shown in the code above, Node constructor works on its own but it does not work when done through the Stack class.
The argument of vector needs a default constructor. Node is missing one, hence the error.
Your issue here is that stack(g_MaxSize) in Stack(): stack(g_MaxSize), top(0)
is requesting that you construct g_MaxSize default constructed Nodes in the vector. You can't do that though since Node is not default constructable.
You can add a default constructor to Node that will fix that. Another way would be to pass a default Node to the vector constructor like stack(g_MaxSize, Node<T>(1)). Lastly you could create the vector with zero size and then call reserve in the constructor body to allocate the storage for the Nodes without constructing them.
Related
I have been learning and playing around C++ (mostly, pointers and dynamic memory allocation) for few days and I tried to create a generic class for linked list.
The classes
#include <cstdint>
#define _LINKEDLIST_DEFAULT_MAX_SIZE 2147483647L
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode;
template <typename T>
class LinkedListNode final
{
private:
LinkedListNode<T> *nextNode{nullptr};
friend LinkedList<T>;
public:
T data{};
};
template <typename T>
class LinkedList final
{
private:
LinkedListNode<T> *firstNode{nullptr};
std::int32_t maxLength{};
std::int32_t currentLength{};
public:
LinkedList(std::int32_t max_size = _LINKEDLIST_DEFAULT_MAX_SIZE)
{
maxLength = max_size;
}
void addFirst(LinkedListNode<T> *nodePtr)
{
if (firstNode == nullptr)
{
firstNode = nodePtr;
return;
}
nodePtr->nextNode = firstNode;
firstNode = nodePtr;
}
void clerList()
{
// code of releasing occupied heap memory back
}
}
Main method
int main()
{
LinkedList<short> *head{new LinkedList<short>()};
LinkedListNode<short> *node1{new LinkedListNode<short>()};
LinkedListNode<short> *node2{new LinkedListNode<short>()};
node1->data = 1;
node2->data = 2;
head->addFirst(node1);
head->addFirst(node2);
return 0;
}
And this works as properly so far as variables in my debugger shows expected results.
But my issue is how could I write my clearList() method on LinkedList<T> class? I can traverse through LinkedListNode<T> objects and release their memory back calling delete(), but calling delete(this) from clearList() to release back the memory of LinkedList<T> object at first sounds like suiciding since it tries to delete the object which it belongs to. (Note that some simple validation logics have not yet been put into the code)
Do you have any ideas to make this happen :)
I am trying to implement a class that represents a doubly-linked list, and I have a function createNode() which returns a new Node (A templated class) with all its members initialized. This function is going to be used to create linked lists where the size is known, but no data has been passed to it. For most data types, this works. However, this does not work for classes without default constructors, since they cannot be initialized without parameters. Here is the minimal code that exhibits this:
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
T value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, T() }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
delete testNode;
}
Basically, my final goal is to be able to create a linked list which can hold uninitialized nodes while keeping track of which nodes are initialized or not. I remember reading in an old textbook of mine about a method for solving this problem that involves using allocators (Which are used for handling construction/destruction of objects), but I don't remember the exact technique at all. So how should I go about this?
Use std::optional<T> if you have access to C++17, or boost::optional<T> if you don't.
template<typename T>
struct Node
{
Node* prev;
Node* next;
std::optional<T> value; // or boost::optional<T> value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, std::nullopt /* or boost::none */ };
}
If you don't have access to C++17 and don't want to include boost, you could roll your own optional template with something like this:
struct nullopt_t {};
nullopt_t nullopt;
template <typename T>
class optional
{
public:
template <typename... Args>
optional(Args&&... args)
: ptr{new ((void*)&storage) T(std::forward<Args>(args)...)}
{}
optional(nullopt_t)
: ptr{nullptr}
{}
~optional()
{
if (ptr) {
ptr->~T();
}
}
optional& operator=(T obj)
{
if (ptr) {
*ptr = std::move(obj);
} else {
ptr = new ((void*)&storage) T(std::move(obj));
}
return *this;
}
explicit operator bool()
{
return ptr != nullptr;
}
T& value()
{
if (!ptr) {
throw std::exception();
}
return *ptr;
}
// Other const-correct and rvalue-correct accessors left
// as an exercise to the reader
private:
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
T* ptr;
};
Live Demo
You can use placement new to place the object later in a pre-allocated memory.
It's just about splitting the memory allocation from the construction of the objects. So you can declare a member in your Node that takes memory but do not construct object because it needs parameter. Later you can construct the object with the needed parameters but not allocate memory with new but use placement new to just call the constructor with memory already allocated within the Node.
So following is an example of a self-made std::optional. In n3527 you can find more details about std::optional.
#include <vector>
#include <functional>
#include <iostream>
#include <algorithm>
#include <string>
#include <memory>
using namespace std;
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
//private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
bool empty = true;
union {
T t;
} value; // Could be replaced with typename std::aligned_storage<sizeof(T), alignof(T)>::type value;
// need a constructor that inits the value union and activate a field
// Node()
~Node() {
if (!empty) {
value.t.~T();
}
}
template<typename... Args>
void setValue(Args... args) {
if (!empty) {
value.t.~T();
}
new (&value.t) T(std::forward<Args...>(args...));
empty = false;
}
T& getValue() {
// TODO:
if (empty) {
//throw
}
return value.t;
}
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
testNode->setValue(42);
if (!testNode->empty) {
std::cout << testNode->getValue().value_;
}
delete testNode;
return 0;
}
Live Demo
With few small changes and with reinterpret_cass you can also use typename std::aligned_storage<sizeof(T), alignof(T)>::type value; - Live Demo
Allocators manage the memory and you will not be able include (aggregate) the object in your class and have to use pointers and second allocation except you use allocator to place the entire Node.
There are interesting presentation form John Lakos about allocators on YouTube - CppCon 2017 Local 'Arena' Memory Allocators part 1 and 2.
What you are asking is literally impossible -- to default construct an object without a default constructor.
Perhaps consider adding a T nodeValue parameter to createNode()? Or change the Node itself so that rather than holding an object, it holds a pointer to the object. That seems like a memory management nightmare, but it could work.
I have been solving a question, Dijkstra's Algorithm, in C++. I've implemented it using adjacency list.
So I have a class for a node, a class for a minHeap, and a class for the Graph.
class node
{
int vertex,weight;
node *next;
friend class Graph;
friend class minHeap;
public:
node();
node(int,int);
};
node::node(){
vertex=weight=0;
next=0;
}
node::node(int v,int wt){
vertex=v;
weight=wt;
next=0;
}
Do I define the minHeap class this way (without a friend function) and create an object in the getDijkSP() function normally, which allows me to use the object only in that function?
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap];
heapSize=-1;
pos=new int[cap]();
} //eliminating other methods
class Graph
{
node **adjList;
int v;
bool *visited;
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
}
void Graph::getDijkSP(){
minHeap hp(v); //here
hp.addElement(node(0,0));
for(int i=1;i<v;i++)
hp.addElement(node(i,INT_MAX));
while(!hp.isempty()){
node temp=hp.extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp.decreaseKey(current->vertex,current->weight+temp.weight);
}
}
(OR) Do I define the minHeap class with a friend function, so that I can create an object of the minHeap class using the new keyword? (And this helps me define the minHeap object in the scope of the Graph class, so that I can use it in all of its functions for other capabilities as well.)
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
friend class Graph; //say like this
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap]();
heapSize=-1;
pos=new int[cap]();
}
class Graph
{
node **adjList;
int v;
bool *visited;
minHeap *hp; //and do this
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
hp=new minHeap(v); //dynamic allocation
}
void Graph::getDijkSP(){
hp->addElement(node(0,0));
for(int i=1;i<v;i++)
hp->addElement(node(i,INT_MAX));
while(!hp->isempty()){
node temp=hp->extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp->decreaseKey(current->vertex,current->weight+temp.weight);
}
}
I have read this and a few other articles, but specifically want to know the advantages, disadvantages and the appropriateness of both the methods for such similar kinds of questions.
I've provided the constructors for the classes for better clarity.
Short answer would be NO. I would suggest you to read up on smart pointers and rewrite this whole mess. In C++ there is no real reason to use manual allocation in so simple project as this ever.
Also instead of assigning 0 or NULL to a pointer use nullptr, which is C++ symbol only for null pointers unlike the previous mentioned C values that are actually just a int 0 which may cause some unintentional errors.
Edit in response to your comment:
So I've decided to rewrite your code using actual modern C++ instead of this C code with simple classes. In your whole example there are almost no pointers or dynamic allocations needed. I wasn't absolutely sure who exactly should own the actual nodes so from the example I assumed that the MinHeap should. Also I didn't get the point of MinHeap::pos and Graph::visited from what I could see. I can explain any part of that code in more detail, just ask which.
Here is the code:
class Node {
// Only friend class required if you insist on keeping members of Node private.
// If they aren't meant to change, consider declaring them as public and const.
template <unsigned Size> friend class Graph;
public:
Node(int v, int wt) : vertex(v), weight(wt) {}
private:
// Default values written in here right after declarations
// There is no need for a default constructor. You never call it anyway.
int vertex;
int weight;
Node* next = nullptr;
};
// Template parameter because of internal use of std::array.
// If the capacity shouldn't be constant, use std::vector and remove template.
template <unsigned Capacity>
class MinHeap {
public:
// No constructor needed
// ---------------------
// One small tip: write parameter names in function declarations
// even if they aren't needed there for better readability of your code.
void addElement(Node n) { /* impl */ }
Node extractMin() { /* impl */ }
unsigned capacity() { return Capacity; }
bool isEmpty() { return heap.isEmpty(); }
private:
// Default values written in here right after declarations
int heapSize = -1;
std::array<Node, Capacity> heap;
};
// Template parameter because of internal use of std::array.
// If the vertex count shouldn't be constant, use std::vector and remove template.
template <unsigned Vertices>
class Graph {
public:
// No constructor needed
// ---------------------
void getDjikSP() {
hp.addElement({0, 0});
for (unsigned i = 1; i < hp.capacity(); ++i)
hp.addElement({0, INT_MAX});
while (!hp.isEmpty()) {
Node tmp = hp.extractMin();
std::cout << tmp.vertex << " " << tmp.weight << std::endl;
for (Node* current = adjList[tmp.vertex]; current != nullptr; current = current->next)
hp.decreaseKey(current->vertex, current->weight + tmp.weight);
}
}
private:
// Default values written in here right after declarations
std::array<Node*, Vertices> adjList;
MinHeap<Vertices> hp;
};
There is still a lot of space for improvements of this code, for example the MinHeaP::extractMin should maybe return Node&& if it is removed from the heap or const Node& if it should return a reference to the top, etc. To address all the problems and inefficiencies this can still have I would need to see the full code with all functions.
I have a generic class Queue that contains a template Ttype2 as the placement holder for the type of data that will be stored in the information field of each node.
In my driver class I want to instantiate an array of Queue class objects but I can't seem to figure it out. How might I go about doing this?
These didn't work but illustrate what I'm trying to accomplish:
// Queue Complex[] = new Queue();//invalid use of template name without identifier list
//Queue<Ttype2> Complex[]; //template arg 1 is invalid
// vector<Queue> Complex2[];//invalid template arguments`
Queue Class declaration and constructor inside Queue.h header:
template <typename Ttype2>
class Queue
{
// Global Data Items
protected:
Node <Ttype2> Front, Rear;
int Length;
// member function prototypes
public:
Queue();
void AddRear(Node <Ttype2> ThisNode);
Node <Ttype2> RemoveFront();
void Modify(int Position, Node <Ttype2> ThisNode);
void ClearAll();
int GetSize();`
Node <Ttype2> GetNode(int Position);
Node <Ttype2>* toArray();
};`
// Constructor
template <typename Ttype2>
Queue <Ttype2> :: Queue()
{
Rear = Front = NULL;
Length = 0;
} // End of Constructor
`
This works:
Queue<int> *Complex = new Queue<int>();
Queue<int> Complex[1];
vector<Queue<int>> Complex2[1];
You need to give real params to your template when instantiating it.
Queue<Ttype2> // Ttype2 isn't a real type, use int, char, ...
Also you need to define your type Node<>. And if your want to assign NULL to Rear and Front it, first consider to make them pointers, second use nullptr instead of NULL.
I will add to Yola's solution that if I want to keep many different Queue<XXX> in a single array,
I usually create an interface class Queue_base.
class Queue_base{
public: virtual void func()=0;
};
template <typename Ttype2>class Queue : public Queue_base{
public: void func(){
//... some code
}
};
int main() {
Queue_base* complex[2];
complex[0]=new Queue<int>();
complex[1]=new Queue<float>();
complex[0]->func();
std::vector<Queue_base*> complex2;
complex2.push_back(new Queue<char>());
Queue<int>* c1=static_cast<Queue<int>*>(complex[0]);
return 0;
}
Here is live demo.
Note that using virtual function reduces performance a bit.
It will also lose the type (reduce to Queue_base*) and restrict some function calling, but it is useful for some real-world cases.
To extend its usage Node<T> can also inherit from a new class Node_Base that has all common function of Node<T>, e.g. :-
template <typename Ttype2> class Queue : public Queue_Base{
// Global Data Items
protected:
Node_Base* Front; //Front = new Node<Ttype2>();
Node_Base* Rear;
It depends on your demand though.
I've been working on updating my old templated linked list to be able to take a complex data type. But I have no idea how to make it be able to return the data element in the node class. Currently the code for my node class looks like this:
using namespace std;
#ifndef Node_A
#define Node_A
template <class T>
class Node
{
public:
Node();
~Node();
T getData();
Node* getNext();
void setData(T);
void setNext(Node*);
private:
Node *next;
T data;
};
template <class T>
Node<T>::Node()
{
next = NULL;
return;
}
template <class T>
Node<T>::~Node()
{
return;
}
template <class T>
T Node<T>::getData()
{
return data;
}
template <class T>
Node<T>* Node<T>::getNext()
{
return next;
}
template <class T>
void Node<T>::setData(T a)
{
data = a;
return;
}
template <class T>
void Node<T>::setNext(Node* a)
{
next = a;
return;
}
#endif
Now this works perfectly fine if the data type T is a primitive but if you use a non-primitive like say a struct it would give a runtime error. I presume because structs don't do operator overloading for = operator. Is there a simple way of fixing this without completely overhauling the class?
It's not about overloading the = operator, it's about implementing the assignment operator for the struct. If you do that, you won't need to change your Node class, unless I've missed something else.
The above assumes that you'll be making copies of the data inside the Node. Alternatively, you can pass the data by reference. In this case, you need to be careful that the data doesn't get deleted before the Node object is deleted, otherwise you'll get a crash when trying to access a deleted data object from your Node.