I'm trying to write a linked-list using class and I want it to have a specific format.
For example if I have three data called p1,p2 and p3 and a linked-list called list; I want to put them in order like blow.
list.insert(p1).insert(p2).insert(p3);
I tried to return the object, but didn't work.
Here's my code.
#include<iostream>
using namespace std;
class linked_list {
public:
int *head;
linked_list();
~linked_list();
linked_list insert(int data);
};
linked_list::linked_list()
{
head = NULL;
}
linked_list::~linked_list()
{
int *temp;
int *de;
for (temp = head;temp != NULL;) {
de = temp->next;
delete temp;
temp = de;
}
delete temp;
//delete de;
}
linked_list linked_list::insert(int data)
{
int *temp;
temp = new int;
*temp = data;
temp->next = NULL;
if (head == NULL) {
head = temp;
}
else {
int* node = head;
while (node->next != NULL) {
node = node->next;
}
node->next = temp;
// delete node;
}
//delete temp;
return *this;
}
int main(){
linked_list l1;
int p1,p2,p3;
l1.insert(p1).insert(p2).insert(p3);
return 0;}
#Jarod42 got your answer, despite all the buggy things around, what you want is something like this.
The function you want to chain must return a reference to your current object instance.
Here is a Foo class that change its _data member and chain multiple time.
#include <iostream>
class Foo
{
private:
int _data;
public:
Foo(int data) : _data(data) {}
~Foo()
{
}
// change the value of data then return a reference to the current Foo instance
Foo &changeData(int a)
{
_data = a;
return *this;
}
void printData()
{
std::cout << _data << std::endl;
}
};
int main()
{
Foo f(1);
f.changeData(2).changeData(3);
f.printData();
}
Note that I'm returning Foo& from the function I'm chaining, that's the little trick that is missing from yours.
Hope it helped you :)
Related
I'm implementing an unordered linked list in C++ based on first principles. My (partially complete so far) implementation is:
#include <iostream>
class Node {
int m_data;
Node *m_next;
public:
Node(int data)
{
m_data = data;
m_next = nullptr;
}
int getData() { return m_data; }
void setData(int data) { m_data = data; }
Node* getNext() { return m_next; }
void setNext(Node *next) { m_next = next; }
};
class UnorderedList {
public:
Node *m_head;
public:
UnorderedList()
{
m_head = nullptr;
}
bool isEmpty() { return m_head == nullptr; }
void appendToHead(int data)
{
Node temp = Node(data);
temp.setNext(m_head);
m_head = &temp;
}
void remove(int data);
bool search(int data);
};
int main()
{
UnorderedList list1;
list1.appendToHead(32);
list1.appendToHead(47);
list1.appendToHead(90);
std::cout << list1.m_head->getData() << '\n';
std::cout << list1.m_head->getNext()->getData() << '\n';
return 0;
}
I am able to correctly print the head of the list as '90', but the next line (i.e. getNext()->getData()) gets printed as a large random number (281314120). What is the reason for this?
void appendToHead(int data)
{
Node temp = Node(data);
temp.setNext(m_head);
m_head = &temp;
}
Never store the address of an object with automatic storage duration. That object (in this case, temp) will cease to exist when appendToHead method completes.
You did that and invoked Undefined Behavior. You probably wanted to do:
void appendToHead(int data)
{
Node* temp = new Node(data);
temp->setNext(m_head);
m_head = temp;
}
You should also consider satisfying The Rule Of Five
Rather than raw pointers, additionally explore the use of std::unique_ptr.
During debugging the second execution of while loop the code below produces an out_of_range exception. I noticed that:
before stack.top():
after stack.top():
Does anyone know why this happens and how to fix it?
#include <iostream>
#include <stack>
#include <vector>
#include <memory>
#include <functional>
int replacement;
int toreplace;
class Node
{
public:
int id_;
std::vector<Node*> children;
Node* at(int i)
{
return children.at(i);
}
std::vector<Node*> GetChildren() {
return children;
}
Node(int id_) {
this->id_ = id_;
}
};
class CPreorderStackFrame
{
public:
Node* node_;
CPreorderStackFrame* root_;
int index_;
explicit CPreorderStackFrame(Node* node_, CPreorderStackFrame* root_, int index_)
{
this->node_ = node_;
this->root_ = root_;
this->index_ = index_;
}
void replaceChildrenByIndex(Node* replace, int index)
{
replace->id_ = node_->at(index)->id_;
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
}
bool hasChildren() {
return !(node_->GetChildren().empty());
}
};
void pre_order_traverse(Node* root,
std::function<std::unique_ptr<Node>(Node*)> visit)
{ // always: root != NULL
std::stack<CPreorderStackFrame> mystack;
mystack.push(CPreorderStackFrame(root, NULL, NULL));
while (!mystack.empty())
{
CPreorderStackFrame cur = mystack.top();
mystack.pop();
std::unique_ptr<Node> replace = visit(cur.node_);
if (replace)
{
cur.root_->replaceChildrenByIndex(replace.release(), cur.index_);
}
else if (cur.hasChildren())
{
for (int i = cur.node_->GetChildren().size() - 1; i >= 0; --i)
{ //preorder requires right to left
Node *topush = cur.node_->at(i);
if (topush)
{
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame); //hier ist noch alles richtig
}
}
}
}
}
std::unique_ptr<Node> print_visit(Node* node) {
std::cout << node->id_ << ' ';
return NULL;
}
std::unique_ptr<Node> replace_visit(Node* node) {
std::cout << node->id_ << ' ';
if (node->id_ == toreplace) {
std::unique_ptr<Node> retval(new Node(replacement));
return retval;
}
return NULL;
}
int main() {
toreplace = 3;
replacement = 8;
Node *a = new Node(1);
Node *b = new Node(2);
Node *c = new Node(3);
Node *d = new Node(4);
Node *e = new Node(5);
Node *f = new Node(3);
Node *g = new Node(3);
Node *h = new Node(42);
Node *i = new Node(42);
a->children.push_back(b);
a->children.push_back(c);
a->children.push_back(d);
a->children.push_back(e);
b->children.push_back(f);
b->children.push_back(g);
b->children.push_back(h);
b->children.push_back(i);
pre_order_traverse(a, replace_visit);
return 0;
}
One problem is
std::vector<Node*> GetChildren()
which means that
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
is destroying an object, but only replacing its address in a copy of the vector.
Dereferencing that element in the original vector is undefined.
You need to return by reference, or move the removal code into Node.
Another problem, and the immediate cause of your observations, is that
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame);
is storing a pointer to the automatic object cur, whose lifetime ends with the end of the iteration.
Dereferencing the pointer after that is undefined.
Most (probably all) compilers will reuse that object's storage for the next iteration, which means that all your CPreorderStackFrames store the same pointer, and not a single one of them is valid by the time you dereference it.
It looks like the root doesn't need to be a pointer at all.
i have recently started studying linkedlist in c++. Although i am finding it pretty confusing but i made some functions to insert and delete and element from the linkedlist.
The program worked fine with int data type. But i want to create a linkedlist of template type and i cannot understand how to do it.
I have tried to create a function to insert the node at the first position of link list but it gives me errors like access specifier needed before node etc ...
#include <iostream>
#include<conio.h>
using namespace std;
template<class T>
class node
{
public:
T data;
node *next;
};
template<class T>
class linklist
{
public:
node <int>*head;
linklist()
{
head = NULL;
}
bool Is_Empty(node <T>*ptr)
{
if(ptr==NULL)
{
return true;
}
return false;
}
void insert_at_head(T num)
{
if(Is_Empty(head))
{
node <T>*temp = new node; // error is on this line. it says access specifier needed before node.
temp->data = num;
head = temp;
temp->next = NULL;
}
else
{
node *temp = new node;
temp->data = num;
head = temp;
temp->next = head->next;
}
}
void show_list(node <T>*ptr)
{
cout<<"\nElements in the List are : ";
while(ptr!=NULL)
{
cout<<ptr->data<<" ";
ptr = ptr->next;
}
}
};
int main()
{
cout << "Hello world!" << endl;
getch()
}
I am facing a problem while coding Linked List implementation in c++. Whenever I am trying to add an element I am getting Segmentation Fault error.
#include <iostream>
class node{
public:
int data;
class node *next;
};
class LinkedList {
public:
node *head;
LinkedList(int num);
void add(int number);
void display();
};
const int null = 0;
LinkedList::LinkedList(int num) {
// TODO Auto-generated constructor stub
std::cout<<"Constructor Called"<<std::endl;
head->data = num;
head->next = null;
std::cout<<"Constructor Call completed"<<std::endl;
}
void LinkedList::add(int num) {
struct node *n=new node;
n->data = num;
n->next = null;
struct node *current = head;
while (current->next != null) {
current = current->next;
}
current->next = n;
}
void LinkedList::display() {
std::cout<<"Display"<<std::endl;
struct node *current = head;
while (current!= null) {
std::cout << current->data << "->";
current = current->next;
}
std::cout << "null"<<std::endl;
}
int main() {
LinkedList l(1);
l.display();
l.add(2);
l.display();
return 0;
}
Please look into the gdb debug logs: node n is not referencing to any memory location. So it could not be initialized. Please let me know in case you require any further information.
Thanks in advance!
struct node *n=new node;
Constructor Called
Constructor Call completed
Breakpoint 1, main () at SampleCPP.cpp:60
60 l.display();
(gdb) s
LinkedList::display (this=0xbffff03c) at SampleCPP.cpp:48
48 std::cout
(gdb) n
51 while (current!= null) {
(gdb) n
52 std::cout data ";
(gdb) n
53 current = current->next;
(gdb) n
51 while (current!= null) {
(gdb) n
55 std::cout null
56 }
(gdb) n
main () at SampleCPP.cpp:61
61 l.add(2);
(gdb) s
LinkedList::add (this=0xbffff03c, num=2) at SampleCPP.cpp:38
38 struct node *n=new node;
(gdb) print n
$2 = (node *) 0x0
(gdb)
You never allocate memory for head. That's your problem.
Allocate it in the constructor:
LinkedList::LinkedList(int num) {
std::cout<<"Constructor Called"<<std::endl;
head = new node; // This is missing!
head->data = num;
head->next = null;
std::cout<<"Constructor Call completed"<<std::endl;
}
and it would be good to free all that memory too before your program finishes..
you are not allocating memory for head; it should be like this
LinkedList::LinkedList(int num) {
// TODO Auto-generated constructor stub
head=new node();
std::cout<<"Constructor Called"<<std::endl;
head->data = num;
head->next = null;
std::cout<<"Constructor Call completed"<<std::endl;
}
With a small modification,
class node{
public:
int data;
class node *next;
node(int num): data(num), next(NULL){}
};
And
LinkedList::LinkedList(int num): head(new node(num)) {
// TODO Auto-generated constructor stub
std::cout<<"Constructor Called"<<std::endl;
//Do sth if you wish
std::cout<<"Constructor Call completed"<<std::endl;
}
This removes some additional complexities. Change where ever you instantiate node with new constructor.
I'd like to suggest the following implementation:
#include <iostream>
using namespace std;
class node
{
private:
int data;
node* next;
public:
// Because of that we store the pointer, default implementations of the
// copying operations are not acceptable -- they can lead to memory leakage.
node(const node&) = delete;
node& operator =(const node&) = delete;
node(int d, node* prev = nullptr) :
data(d), next(nullptr)
{
if(prev)
{
// Free memory before assigning the pointer.
delete prev->next;
prev->next = this;
}
}
~node()
{
// Deletes up to the end of the subchain.
delete next;
}
inline node* getNext() const
{
return next;
}
inline operator int() const
{
return data;
}
};
class LinkedList
{
private:
node* head;
node* curr;
public:
LinkedList(int first_entry) :
head(new node(first_entry)), curr(head)
{}
~LinkedList()
{
delete head;
}
void add(int entry)
{
curr = new node(entry, curr);
}
void display() const
{
for(node* i = head; i; i = i->getNext())
cout << (int)*i << "->";
cout << "null" << endl;
}
};
int main(int argc, char* argv[])
{
LinkedList l(1);
l.display();
l.add(2);
l.display();
return EXIT_SUCCESS;
}
In this approach, an additional attention was drawn to the memory management. As well it uses the OOP more intensively.
MySinglyLinkedList.h:
#include <iostream>
template<class T> class LinkedList;
template<class T>
class LinkedNode {
public:
LinkedNode(T new_data):data(new_data) {; }
private:
friend class LinkedList<T>;
LinkedNode<T> *next;
T data;
};
template<class T>
class LinkedList {
public:
LinkedList();
~LinkedList();
void PushNode(T new_data);
void Delete(LinkedNode<T> *pnode);
void Show();
private:
LinkedNode<T> *head; //Head pointer
LinkedNode<T> *tail; //Tail pointer
int length; //Length of the list
};
//Initialize an empty list when creating it
template<class T>
LinkedList<T>::LinkedList()
{
head = tail = NULL;
length = 0;
}
//delete all the nodes when deconstructing the object
template<class T>
LinkedList<T>::~LinkedList()
{
LinkedNode<T> *ptr = head;
while (ptr)
{
LinkedNode<T> *ptr_del = ptr;
ptr = ptr->next;
Delete(ptr_del);
}
}
//Add one node to the tail of the list
template<class T>
void LinkedList<T>::PushNode(T new_data)
{
LinkedNode<T> *pnew_node = new LinkedNode<T>(new_data);
pnew_node->next = NULL;
if (!length) {
head = tail = pnew_node;
length++;
} else {
tail->next = pnew_node;
tail = pnew_node;
length++;
}
}
//Delete the node pointed by pnode
template<class T>
void LinkedList<T>::Delete(LinkedNode<T> *pnode)
{
LinkedNode<T> *ptr = head;
if (pnode==head) {
head = pnode->next;
} else {
while(ptr->next != pnode)
{
ptr = ptr->next;
}
ptr->next = pnode->next;
}
if(pnode == tail)
tail = ptr;
delete pnode;
length--;
}
template<class T>
void LinkedList<T>::Show() //Print all the contents in the list
{
LinkedNode<T> *pnode = head;
while(pnode)
{
std::cout << pnode->data << std::endl;
pnode = pnode->next;
}
std::cout << "In total: " << length << std::endl;
}
The main function is as follows:
#include "MySinglyLinkedList.h"
#include <cstdlib>
#include <ctime>
using namespace std;
int main(int argc, char *argv[])
{
//list_len is the length of the list
int list_len = 5;
srand(time(0));
if (argc > 1)
list_len = atoi(argv[1]);
LinkedList<int> test_list; //Create the first list: test_list
for (int i = 0; i < list_len; i++)
{
//The elements in the list are random integers
int cur_data = rand()%list_len;
test_list.PushNode(cur_data);
}
test_list.Show();
LinkedList<int> test2 = test_list; //Create the second list: test2
test2.Show();
return 0;
}
Since I didn't define any copy constructor here, the default copy constructor will be called and do the bit copy when creating the second list, and as a result test_list and test2 will point to the same linked list. Therefore the first node of the list will be deleted twice when the two object are deconstructed. But the fact is nothing wrong happened when I compiled the program using GCC, and it ran successfully in Linux. I don't understand why no error occurred.
Deleting a pointer that has already been deleted causes undefined behavior, so anything can happen. If you want to make sure nothing happens, set the pointer to null after deletion. Deleting null does nothing, and it won't cause an error.
See: c++ delete (wikipedia)
As per Diego's answer, the C++ standard permits deleting NULL pointers. The compiler has no way to know what value your pointer will contain when you delete it the second time (i.e. it might be NULL), therefore it has no choice but to allow it in order to comply with the standard.