I have a misunderstanding here. I'm designing a Queue class which uses the Client class as the base unit. The list structure consists of a pointer to the next data and a variable for holding the Client object.
The Queue class has 2 ways of operating. The way of it's operating is determined by the bool MODE variable. If mode equals 1, then the Queue class uses placement new operator, and if not, it uses the new operator.
This is the Queue class's prototype:
class Queue
{
private:
const int max_lists;
int no_lists, counter;
char client_value;
list *chunk;
list *top;
const bool MODE;
void addFirst(const Client &c);
void addLast(const Client &c);
void deleteLast();
void deleteFirst();
void clean_mem();
void clean_mem(list *&pos);
list* malloc();//T* type
public:
Queue();
Queue(list *buffer,int no);
Queue(const Queue &q);
Queue& operator=(const Queue &q);
~Queue() { clean_mem(); }
void enqueue(const Client &c);
void timeoutCustomers();
void decreaseTimeout();
Client getCustomer() const;
void finishCustomer();
void show() const;
};
The functions definitions which contribute to the error given are here:
void Queue::addFirst(const Client &c)
{
if(top==nullptr)
{
top = malloc();
top->info = c;
top->next = nullptr;
}
else
{
list *add = malloc();
add->info = c;
add->next = top;
top = add;
}
}
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}
And here's the list structure:
struct list { Client info; list *next; };
When I make an instance of the Queue class, I can choose whether I go on placement new or just the new operator.
If I choose the placement new, I'm have to send the address of an array of type list. The address is saved into chunk pointer. The top pointer holds the first address of the linked list.
Then, if I call the addFirst() function it stops at top->info = c. The error points to top->info :
CXX0030: Error: Expression cannot be evaluated.
But when I switch back to new operator, everything works. This tells me that there's a problem with the allocation of a new portion in the already allocated memory.
Can somebody give me a direction of what's the problem here?
Did you intend your malloc function like that? You have an 'else' block AFTER your functions definition and not all control paths return a value. I have a rewrite here that seems to match more with what I think you actually intend:
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}
Related
So i am trying to create a c++ file which implements stack and all its functions(push,pop,getTop,etc). I want to use Template so that i can make this Stack class for multiple datatypes. I am using linked list to store the data. Here is some example of stack i have implemented using linked list.
#include<iostream>
using namespace std;
template <class T>
class Node{
public:
T data;
Node *next;
Node()
{
next = NULL;
}
};
class Stack
{
Node *top;
public:
Stack();
int isEmpty();
int isFull();
void push(T data);
T pop();
void display();
};
Stack :: Stack()
{
top = NULL;
}
int Stack :: isEmpty()
{
if(top == NULL)
{
return 1;
}
else
{
return 0;
}
}
int Stack :: isFull()
{
int temp;
Node *t = new Node;
if(t==NULL)
{
temp = 1;
}
else
{
temp = 0;
}
delete t;
return temp;
}
void Stack :: push(T data)
{
Node *n;
if(isFull())
{
cout<<"\nStack overflow";
}
else
{
n = new Node;
n->data = data;
n->next = top;
top = n;
}
}
int Stack :: pop()
{
Node *t;
T temp;
if(isEmpty())
{
return temp;
}
else
{
t = top;
top = top->next;
temp = t->data;
delete t;
return temp;
}
}
void Stack :: display()
{
Node *p = top;
while(p != NULL)
{
cout<<"\n"<<p->data;
p = p->next;
}
}
So this is a preview of what i am trying to do, but i don't want to create different node and stack class for different data types. How can i achieve that using Templates. I tried it myself but i am getting lots of error and cant seem to understand why.
Thanks.
I suggest making the Node into an inner class of Stack. There's no need for users to be able to see it.
#include<iostream>
#include<utility>
template<class T>
class Stack {
struct Node { // inner class
T data;
Node *next;
};
Node* top = nullptr;
size_t m_size = 0;
public:
Stack() = default;
// rule of five - no copying, only moving allowed
Stack(const Stack&) = delete;
Stack(Stack&& rhs) noexcept :
top(std::exchange(rhs.top, nullptr)), m_size(rhs.m_size)
{}
Stack& operator=(const Stack&) = delete;
Stack& operator=(Stack&& rhs) noexcept {
std::swap(top, rhs.top);
m_size = rhs.m_size;
return *this;
}
~Stack() {
while(top) {
delete std::exchange(top, top->next);
}
}
bool empty() const { return m_size == 0; }
size_t size() const { return m_size; }
void push(const T& data) {
top = new Node{data, top};
++m_size;
}
T pop() {
T rv = std::move(top->data);
delete std::exchange(top, top->next);
--m_size;
return rv;
}
};
Demo
You can implement like bellow:
#include<iostream>
using namespace std;
template <typename Type>
class Node
{
public:
Type data;
Node<Type> *next;
};
template <typename Type>
class Stack
{
public:
Node<Type> *top;
void push(Type data);
Type pop();
};
int main()
{
}
Implementing a stack with a linked list requires simply storing a linked list privately, and constraining it with the stack's interface. The constraining is the key. The template parameter is the type you are storing in your stack.
The simplest* way is to take the time implement a linked list well, so that you only have to worry about constraining it in your stack class and not writing a linked list to behave like a stack in your stack class. The principle at play here is called Separation of Concerns.
Here's a quick example using std::list for simplicity's sake:
template <typename T>
class Stack {
public:
Stack() = default;
Stack(T val) : m_stack(val) {}
void push(T val) { m_stack.push_front(val); }
T& top() { return m_stack.front(); }
void pop() {
if (!m_stack.empty()) m_stack.pop_front();
}
bool empty() const { return m_stack.empty(); }
private:
std::list<T> m_stack{};
};
The if statement might not be necessary in the pop() function if you want the exception to be thrown in your stack.
Here's a main() that tests the stack:
int main() {
Stack<int> s1;
for (int i = 1; i < 11; ++i) s1.push(i);
while (!s1.empty()) {
std::cout << s1.top() << ' ';
s1.pop();
}
std::cout << '\n';
Stack<char> s2('A');
for (char l = 'B'; l != 'K'; ++l) s2.push(l);
while (!s2.empty()) {
std::cout << s2.top() << ' ';
s2.pop();
}
std::cout << '\n';
}
My only includes are <iostream> and <list>. The output:
10 9 8 7 6 5 4 3 2 1
J I H G F E D C B
I am able to avoid a lot of unnecessary work like the Rule of 5 because std::list handles it all for me. So I am fine with compiler-provided copy and move constructors and the destructor.
* This is much easier said than done. I keep a simple linked list around for those specific questions, and it is still ~130 lines of code, and does not have all the functionality necessary to be properly constrained to behave like a stack like I demonstrate with std::list.
If you've written a linked list already, the stack should be very simple as successfully writing a linked list requires demonstrating an extremely wide range of C++ knowledge and programming principles.
So i have a Linked list implementation of my own and it can successfully keep integers and call them when needed with overloaded [] operator but when it comes to storing a class in my linked list, it seems that i can't call the class appropriately (using the same [] operator).
Called functions and members of my Linked List;
#include <iostream>
#include <assert.h>
template<typename T>
struct node {
T data;
node<T>* next;
};
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
void insert(T value) {
last->next = new node<T>;
last = last->next;
last->data = value;
last->next = NULL;
if (isEmpty()) {
head = last;
}
lenght++;
}
node<T>* search(int indx) {
node<T>* current;
current = head;
int count=0;
while (current != NULL) {
if (count == indx) {
break;
}
current = current->next;
count++;
}
return current;
}
T& operator [](int indx) {
assert(indx >= lenght - 1);
T result;
result = search(indx)->data;
return result;
}
};
And here is the main function and the class that i try to store;
#include <iostream>
#include <fstream>
#include <string>
#include "VectemLibrary.h"
class word {
public:
std::string value;
int count;
word(std::string value, int count): value(value),count(count) {
}
word() {
value = "NOT ASSIGNED";
count = 0;
}
word(const word& w1) {
value = w1.value;
count = w1.count;
}
~word() {
std::cout << "Word Destroyed" << std::endl;
}
};
int main()
{
Vectem<word> wordContainer;
word newWord("hello", 1);
wordContainer.insert(newWord);
std::cout << wordContainer[0].value;
}
Visual studio gave me the expection with this message at the last line where i call the first member of linked list with [];
Exception thrown at 0x7A0CF3BE (ucrtbased.dll) in Top 10 words.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I think that my lack of experience with pointers may have caused the problem but if you see something that i can't, Please enlighten me.
There are other problems with the code you posted as well (e.g. isEmpty() is not declared or defined), but I'll focus on the issue you explicitly mentioned.
In your operator:
T& operator [](int indx) {
assert(indx >= lenght - 1);
// You declare this variable on the stack
T result;
result = search(indx)->data;
// And then you return this variable by reference; this is not okay
return result;
}
As mentioned in my code comments (and by #Johnny Mopp in his comment to your post), you shouldn't (can't) return a reference or pointer to a variable declared within the returning function and constructed on the stack. Anything on the stack will be destroyed once the function call ends, so any returned pointers or references to such variables will be dangling references; using said pointers or references will result in undefined behavior.
So you don't want to return a reference to a stack-allocated variable like result; you want to return a reference to the data within the node itself (which is allocated on the heap by insert()), as it will still be a valid reference after the function returns:
return search(indx)->data;
There are several problems with your code, but the most important is that you are not initializing the head, last, or lenght members of Vectem at all. An Access Violation error at address 0xCCCCCCCC is a good indication that uninitialized memory is being accessed, as some compilers/setups fill uninitialized memory with 0xCC bytes, thus head and last are initially 0xCCCCCCCC in your case.
You need to add appropriate constructors to Vectem (as well as a destructor, a copy constructor, and a copy assignment operator, per the Rule of 3), eg:
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
Vectem() : head(NULL), last(NULL), lenght(0) {}
Vectem(const Vectem &src) : head(NULL), last(NULL), lenght(0)
{
// copy src's data to *this as needed ...
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
...
};
Or, in C++11 and later, you can initialize the members directly in their declarations (also, be sure to add a move constructor and a move assignment operator, per the Rule of 5), eg:
template<typename T>
class Vectem {
private:
node<T>* head = nullptr;
node<T>* last = nullptr;
int lenght = 0;
public:
Vectem() = default;
Vectem(const Vectem &src)
{
// copy src's data to *this as needed ...
}
Vectem(Vectem &&src) : head(src.head), last(src.last), lenght(src.lenght)
{
src.head = nullptr;
src.last = nullptr;
src.lenght = 0;
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
Vectem& operator=(Vectem &&rhs)
{
// clear *this as needed...
head = rhs.head; rhs.head = nullptr;
last = rhs.last; rhs.last = nullptr;
lenght = rhs.lenght; rhs.lenght = 0;
return *this;
}
...
};
That being said, insert() is also buggy, as it is dereferencing last before checking that last is actually pointing at a valid node. Try something more like this instead:
void insert(T value) {
node<T> *n = new node<T>{value, NULL};
if (!head) head = n;
if (last) last->next = n;
last = n;
++lenght;
}
Alternatively:
void insert(T value) {
node<T> **p = (last) ? &(last->next) : &head;
*p = new node<T>{value, NULL};
last = *p;
++lenght;
}
I would be very grateful for some help. In my computer science class, we're being asked to do something I've never done before, and I don't understand my problem well enough to even know what terms to Google.
We have three files. lists.h, lists.cpp and driver.cpp
lists.h - this was provided by the professor and CANNOT be altered by me. It's the base class from which I will derive a new class in...
lists.cpp - Here I implement and doubly-linked list in class DLList. I've done dll before, but not this way. So you'll see a lot of code here despite me not being able to test any of it. Don't worry if my functions are wrong here, I'm simply trying to create a doubly linked list in ...
driver.cpp - this is the file I'll be using to test my functions in class DLList.
So anyway, I compile and get ....
g++ -c -g -Wall -std=c++11 driver.cpp
driver.cpp: In function ‘int main()’:
driver.cpp:12:5: error: ‘DLList’ was not declared in this scope
DLList<int> mylist;
^
I understand the error. I've seen this before when a function/class/etc is not being seen by main. In simpler code, it is because it is after main. But here, I just don't know how to fix it. Obviously, driver.cpp cannot see my code in lists.cpp.
Here is my code --
the unalterable lists.h
template<typename E> class List {
private:
void operator =(const List&) {} // Protect assignment
List(const List&) {} // Protect copy constructor
public:
List() {} // Default constructor
virtual ~List() {} // Base destructor
// Clear contents from the list, freeing memory
virtual void clear() = 0;
// Insert an element at the beginning of the list.
virtual void prepend(const E& item) = 0;
// Append an element at the end of the list.
virtual void append(const E& item) = 0;
// Extra credit: Insert an element at the current location, if possible;
// return true if successful, false if there is no current element
virtual bool insert(const E& item) = 0;
// Extra credit: Remove and assign to item the current element, if possible;
// return true if successful, false if there is no current element
virtual bool remove(E& item) = 0;
// Set the current position to the first element of the list, if possible;
// return true if successful, false if list was empty
virtual bool moveToStart() = 0;
// Set the current position to the last element of the list, if possible;
// return true if successful, false if list was empty
virtual bool moveToEnd() = 0;
// Move the current position one step right, if possible;
// return true if successful, false if already at the end
virtual bool next() = 0;
// Move the current position one step left, if possible;
// return true if successful, false if already at the beginning
virtual bool prev() = 0;
// Return a pointer to the current element (or NULL if none)
virtual const E* getValue() const = 0;
// Return total number of active nodes
virtual int numActive() = 0;
// Return total number of free nodes
virtual int numFree() = 0;
};
// Factory function
template<typename E> List<E> *createList();
lists.cpp
#include "lists.h"
#include <cstddef>
#include <iostream>
using namespace std;
// Doubly linked list link node with freelist support
template <typename E> class Link {
private:
// required by Lab 4
static int free; // # of nodes free
static int active; // # of nodes in use
static Link<E> *freelist; // Reference to freelist head
E element; // Value for this node
Link *next; // Pointer to next node in list
Link *prev; // Pointer to previous node
public:
// Constructors
Link(const E& it, Link *prevp=NULL, Link *nextp=NULL) {
element = it;
prev = prevp;
next = nextp;
}
Link(Link *prevp =NULL, Link *nextp =NULL) {
prev = prevp;
next = nextp;
}
void * operator new(std::size_t) { // Overloaded new operator
active++; // add to active count
if (freelist == NULL) { // Create space
return ::new Link; // ::new means use the standard c++ new operator
}
Link<E> *temp = freelist; // Can take from freelist
freelist = freelist->next;
free--; // will only subtract if we take from freelist
return temp; // Return the link
}
// Overloaded delete operator
void operator delete(void* ptr) {
free++;
active--;
// eliminate the Link being deleted from the active list
Link *prev_tmp=((Link<E>*)ptr)->prev;
Link *next_tmp=((Link<E>*)ptr)->next;
prev_tmp->next=next_tmp;
next_tmp->prev=prev_tmp;
((Link<E>*)ptr)->next = freelist; // Attach deleted Link to the head of the freelist
freelist = (Link<E>*)ptr; // Now redefine the freelist to the new head
}
E get_data() const {
return element;
}
E set_data(E& it) {
element=it;
}
Link<E> *get_next() const {
return next;
}
Link<E> *get_ptrb() const {
return prev;
}
void set_next(Link<E> *new_next ) {
next = new_next;
}
void set_prev(Link<E> *new_prev) {
prev = new_prev;
}
int get_free() {
return free;
}
int get_active(){
return active;
}
};
// The freelist head pointer is actually created here
template <typename E>
Link<E> *Link<E>::freelist = NULL;
template <typename E> class DLList: public List<E> {
private:
Link<E> *head; // Pointer to list header
Link<E> *tail; // Pointer to last element
Link<E> *curr; // Access to current element
void operator =(const DLList&) {} // Protect assignment
DLList(const DLList&) {} // Protect copy constructor
public:
// Default constructor
DLList() {
head=NULL;
tail=NULL;
}
// Base destructor
~DLList() {
//delete
}
// Clear contents from the DLList, freeing memory
void clear() = 0;
// Insert an element at the beginning of the DLList.
void prepend(const E& item) {
Link<E> *newLink = new Link<E>(item);
if (head==NULL) {
head=newLink;
tail=newLink;
curr=newLink;
}
else {
newLink->set_next(head);
head=newLink;
curr=newLink;
}
}
// Append an element at the end of the DLList.
void append(const E& item) {
Link<E> *newLink = new Link<E>(item);
if (head==NULL) {
head=newLink;
tail=newLink;
curr=newLink;
}
else {
tail->set_next(newLink);
tail=newLink;
curr=newLink;
}
}
void print_list() {
if (head==NULL) {
cout << "EMPTY LIST" << endl;
}
else {
Link<E> *temp_ptr = head;
int index=0;
while(temp_ptr) {
cout << "Link " << index++ << ": " << temp_ptr->get_data() << endl;
temp_ptr = temp_ptr->get_next();
}
}
}
// Extra credit: Insert an element at the current location, if possible;
// return true if successful, false if there is no current element
bool insert(const E& item) {
if (curr==NULL) {
return false;
}
else {
Link<E> *newLink = new Link<E>(item);
Link<E> *prev_ptr=curr->get_prev;
Link<E> *next_ptr=curr->get_next();
prev_ptr->set_next(curr);
curr->set_prev(prev_ptr);
next_ptr->set_prev(curr);
curr->set_next(next_ptr);
return true;
}
}
// Extra credit: Remove and assign to item the current element, if possible;
// return true if successful, false if there is no current element
bool remove(E& item) {
if (curr==NULL) {
return false;
}
else {
curr->set_data(item);
}
}
// Set the current position to the first element of the DLList, if possible;
// return true if successful, false if DLList was empty
bool moveToStart() {
if (head==NULL) {
return false;
}
else {
curr=head;
return true;
}
}
// Set the current position to the last element of the DLList, if possible;
// return true if successful, false if DLList was empty
bool moveToEnd() {
if (head==NULL) {
return false;
}
else {
curr=tail;
return true;
}
}
// Move the current position one step right, if possible;
// return true if successful, false if already at the end
bool next() {
if (curr==tail) {
return false;
}
else {
curr=curr->get_next();
return true;
}
}
// Move the current position one step left, if possible;
// return true if successful, false if already at the beginning
bool prev() {
if (curr==head) {
return false;
}
else {
curr=curr->get_prev();
return true;
}
}
// Return a pointer to the current element (or NULL if none)
const E* getValue() {
if (curr==NULL) {
return NULL;
}
else {
curr->get_data();
}
}
// ******** MIGHT HAVE TO GET THIS DATA FROM MULTIPLE SOURCES IF THE PTR IS NULL!!
// BUG !
// Return total number of active nodes
int numActive() {
return curr->get_active();
}
// ******** MIGHT HAVE TO GET THIS DATA FROM MULTIPLE SOURCES IF THE PTR IS NULL!!
// BUG !
// Return total number of free nodes
int numFree() {
return curr->get_free();
}
};
// Explicit instantiation
template List<int> *createList();
driver.cpp
#include <iostream>
#include "lists.h"
using namespace std;
void uppercaseify(string& mystr) {
for (auto& c: mystr)
c = toupper(c);
}
int main() {
createList<int>();
DLList<int> mylist;
return 0;
}
I think you are not supposed to explicitly instantiate your DLList class in main(). This can't work because you don't have the declaration of it available in "driver.cpp".
What you should do instead is implement the factory function in "list.cpp" to return a dynamically allocated instance of your DLList:
template<> List<int> *createList() { return new DLList<int>; }
So the call to createList<int>() in "driver.cpp" will then create an instance of your DLList which you can test through the interface of List:
int main() {
// Create a DLList through factory function.
List<int>* list = createList<int>();
// Use the DLList through the List interface.
list->append( ... );
// Finished with using list, free the memory
delete list; list = nullptr;
// Not necessary - we have created the DLList through factory function!
// DLList<int> mylist;
return 0;
}
Well you're right, the error is there because there is no DLList type declared in your driver file. The easiest option to fix it would be to include your list.cpp file into your driver file
#include "list.cpp"
Generally when you're working with a .h and a .cpp file that have the same name they should refer to the same class. So if you were writing this example outside of a class exercise you would probably name your list.cpp file DLList.h (note that template classes should be in a .h file).
I want to independently overload operator+ to concatenate 2 double chained lists. My idea is to obtain the address of the first element from the first list and the address of the first element from the second list.
In DoubleChainedList class, except the constructor, destructor and the next 4 methods which are working fine, I made a method called get_prim which is supposed to get me the address of the first element from the specified list. Then, using the method get_current I want to move through the first list until it ends while adding in the third list the elements, and then apply the same principle to the second list.
But I have a problem, I get
'get_prim' was not declared in this scope
and
'get_current' was not declared in this scope
at the bolded tagged lines (see the code below) when I compile. What am I missing?
#include <iostream>
#include <stdlib.h>
using namespace std;
//Create node class
class Node
{
private:
float value;
Node *back;
Node *next;
public:
Node *set_value (Node *x, float element) { x->value=element; return x; }
float get_value (Node *x) { return x->value; }
Node *set_back (Node *x) { return x->back; }
Node *set_next (Node *x) { return x->next; }
Node *set_back_nod (Node *x, Node *y) { x->back=y; return x; }
Node *set_next_nod (Node *x, Node *y) { x->next=y; return x; }
void next_to_2next (Node *x) { x->next=x->next->next; }
void next_back_to_origins (Node *x) { x->next->back=x; }
};
//Create list class
class DoubleChainedList : public Node
{
private:
Node *prim;
Node *ultim;
public:
DoubleChainedList() { prim=NULL; ultim=prim; } //Constructor
~DoubleChainedList(); //Destructor
void insert_back(float element); //Inserts an element at the end of the list
void delete_element_from_position(int delete_position); //Deletes from the list the element whose position is equal to "delete_position"
void show_left_right(); //Shows the list from the first element to the last one
void show_right_left(); //Shows the list from the last element to the first one
Nod *get_prim (DoubleChainedList myList) { return this->prim; }; //Intended to obtain the address of the first element from "myList"
Nod *get_current (Node *x) { return set_next(x); }; //Intended to move me through the list
};
DoubleChainedList operator+ (DoubleChainedList myList1, DoubleChainedList myList2)
{
DoubleChainedList myList3;
Nod *current1,*current2;
current1=get_prim(myList1); // ERROR OVER HERE!
current2=get_prim(myList2);
cout<<get_value(current1)<<" "; // ERROR OVER HERE!
cout<<get_value(current2)<<" ";
return myList3;
}
int main()
{
int i,number_elem_myList1,number_elem_myList2,element;
DoubleChainedList myList1,myList2,myList3;
cin>>number_elem_myList1;
for (i=0;i<number_elem_myList1;i++)
{
cin>>element;
myList1.insert_back(element);
}
cin>>number_elem_myList2;
for (i=0;i<number_elem_myList2;i++)
{
cin>>element;
myList2.insert_back(element);
}
myList3=myList1+myList2;
return 0;
}
If you implement operator+= as a member function, you can have access to the other list's variables.
I would implement operator+=, then traverse the other list, appending the other list's nodes to this list.
And pass the other list as const &.
Functions called with e.g. someObject.function(...) or someObject->function(...) (where someObject is respectively either an object or a pointer to an object of some class that has a function(...) function) have direct access to the members of someObject.
So functions that are members of a class doesn't need to be passed an object of that class as parameter, unless you want to work with 2 objects in that function.
The functions of Node should probably look more like:
void set_value (float element) { value = element; }
float get_value () { return value; }
Node *set_back () { return back; }
Node *set_next () { return next; }
void set_back_nod (Node *y) { back = y; }
void set_next_nod (Node *y) { next = y; }
void next_to_2next () { next = next->next; }
void next_back_to_origins () { next->back = this; }
Also, get_prim:
Node *get_prim() { return prim; };
Which then leads to a operator+ which looks more like: (const & as Thomas suggested)
DoubleChainedList operator+ (const DoubleChainedList &myList1,
const DoubleChainedList &myList2)
{
DoubleChainedList myList3;
Node *current1, *current2;
current1 = myList1.get_prim();
current2 = myList2.get_prim();
cout << current1->get_value() << " ";
cout << current2->get_value() << " ";
// ...
return myList3;
}
Using operator+= as Thomas suggested is probably also a better idea.
Modified the program as follows, but I still have a problem. If I try to display the list outside the procedure "operator+", I get "Segmentation fault" (when I debugged the program it happened immediately after this instruction: "myList3=myList1+myList2;"). If I display it inside that procedure, everything's OK. I think that this is happening because of that "return" statement and because I return a temporary object which will no longer exists after the "operator+" procedure ends, but I don't know how to fix that.
#include <iostream>
using namespace std;
//Create node class
class Node
{
private:
float value;
Node *back;
Node *next;
public:
Node *set_value (float element) { value=element; return this; }
float get_value () { return value; }
Node *set_back () { return back; }
Node *set_next () { return next; }
Nod *set_back_node (Node *y) { back=y; return this; }
Nod *set_next_node (Node *y) { next=y; return this; }
void next_to_2next () { next=next->next; }
void next_back_to_origins () { next->back=this; }
};
//Create list class
class DoubleChainedList : public Node
{
private:
Node *prim;
Node *ultim;
public:
DoubleChainedList() { prim=NULL; ultim=prim; } //Constructor
~DoubleChainedList(); //Destructor
void insert_back(float element); //Inserts an element at the end of the list
void delete_element_from_position(int delete_position); //Deletes from the list the element whose position is equal to "delete_position"
void show_left_right(); //Shows the list from the first element to the last one
void show_right_left(); //Shows the list from the last element to the first one
Node *get_prim () { return prim; } //Intended to obtain the address of the first element from a list
};
DoubleChainedList operator+ (DoubleChainedList myList1, DoubleChainedList myList2)
{
DoubleChainedList myList3;
Node *current1,*current2,*current3;
current1=myList1.get_prim();
current2=myList2.get_prim();
while ((current1!=NULL)||(current2!=NULL))
{
if (current1!=NULL)
{
myList3.insert_back(current1->get_value());
current1=current1->set_next();
}
else
if (current2!=NULL)
{
myList3.insert_back(current2->get_value());
current2=current2->set_next();
}
}
//myList3.show_left_right();
//cout<<endl;
//myList3.show_right_left();
return myList3;
}
int main()
{
int i,number_elem_myList1,number_elem_myList2,element;
DoubleChainedList myList1,myList2,myList3;
cin>>nr_elem_lista1;
for (i=0;i<number_elem_myList1;i++)
{
cin>>element;
myList1.insert_back(element);
}
cin>>number_elem_myList2;
for (i=0;i<number_elem_myList2;i++)
{
cin>>element;
myList2.insert_back(element);
}
myList3=myList1+myList2;
myList3.show_left_right();
myList3.show_right_left();
return 0;
}
#Dukeling modified the methods of the "Node" class as you said (and of course the program where necessary) and it's OK, too.
I can post the full code if is someone interested, but it has more than 200 lines, the name of variables/dates, procedures/methods and also some comments wrote in Romanian (my natural language) and it would be harder for someone new to understand it.
I'm a complete noob with dynamically allocated memory. Will this have a memory leak or any other memory problem?
#include <iostream.h>
template <class T> class stack
{
struct node
{
T value;
node* next;
};
public:
stack()
{
size = 0;
}
~stack()
{
while(size > 0)
{
node *n = top->next;
delete top;
top = n;
size--;
}
}
void push(T value)
{
node *n = new node;
n->value = value;
if(size == 0)
{
top = n;
}
else
{
n->next = top;
top = n;
}
size++;
}
T pop()
{
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
else
{
node* n = top;
int val = n->value;
top = n->next;
delete n;
size--;
return val;
}
}
int getSize()
{
return size;
}
private:
int size;
node *top;
};
I don't see any memory management errors -- but I do see several other kinds of errors. For example, what happens when T is something other than int? :)
Also, implementing a stack as a linked list is wasteful and will perform relatively poorly when compared to a deque or vector implementation like that used by std::stack.
In addition to the other excellent answers, one more note:
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
I would suggest thinking about either an assert or an exception here. exit is a bit rash, but if you decide to exit, do not exit with 0: that typically indicates success, which is the last thing you want in an error.
You missed the copy constructor/assignment operator of Stack.
When you create objects of Stack::Node you do not always initialization the next member. Write constructor destructor for stack node and everything else becomes simple.
#include <iostream.h>
template <class T> class stack
{
/*
* The stack object contains a RAW pointer (top)
* So when the object is copied with either copy constructor or
* assignment operator when need to handle that fact. The simplist way
* to handle is to make sure it can not happen. To do this make them
* private (You do not need to define them as they can't be used).
*/
Stack(Stack const&); // Not defined
Stack operator=)(Stack const&); // Not defined
struct Node
{
// Initialize Node
Node(Node* n, T v)
:next(v)
,value(v)
{}
~Node() // Destroy whole chain.
{ delete next;
}
// Data
T value;
Node* next;
};
public:
stack()
:size(0)
,top(NULL)
{}
~stack()
{
/// destructor is now simple
delete top;
}
void push(T value)
{
/// As is the push.
top = new node(top, value);
++size;
}
T pop()
{
/// The pop is just the same.
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
else
{
node* n = top;
T val = n->value;
top = n->next;
n->next = NULL; // Set to NULL to stop the delete chaining.
delete n;
size--;
return val;
}
}
// Make this method a constant.
// As it does not change the object.
int getSize() const
{
return size;
}
private:
int size;
node *top;
};
a few other tips:
instead of simulating the stack internally just use a normal list where you have a pointer to the first and last element of the list, there is no need to mimic a stack internally as long as you provide the push/pop functionality.
i would also skip the 'size' member altogether, instead just count the nodes in the list. this way you don't need to keep the size counter and the list synchronized. Just make sure you initialize the pointers to NULL. calculating size would then look something like:
for(Node* p=first; p!=NULL; p=p->next) ++size;