WHy does this code cause segmentation fault?
It causes seg fault in destructor.
But when I call the free function without destructor, it's ok.
Some answers does not understand the problem.
The problem is that If I use the free function in the main()
s.free();
It works fine..
But I make the destructor do the free() job, it is not OK.
#include<iostream>
using namespace std;
class Stack
{
public:
int pop() {
data = next->data;
auto tmp = next;
next = next->next;
delete tmp;
return data;
}
void push(int n) {
Stack* p = new Stack();
p->data = n;
p->next = next;
next = p;
size++;
}
virtual ~Stack() {
free();
}
void free() {
while(next) pop();
}
Stack* next = nullptr;
protected:
int data;
int size = 0;
};
int main()
{
Stack s;
for(int i=0; i<30; i++) s.push(i);
}
Your pop function destroys the entire stack. It deletes the tmp node (by calling the Stack destructor), which still points to the new next.
And since the Stack destructor calls delete on next, you get a mess of multiple destructor calls on the same objects.
JMA beat me to it by a few seconds, so refer to their code fix for a quick solution.
However, I would recommend you add a dedicated Node struct instead of composing Stacks, it will actually increase the clarity of your code.
In the constructor of the class you must set next = nullptr, otherwhise the loop in the free() function won't stop.
Edit:
I think the problem is because on the pop you delete, and that calls the destructor again.
try this one:
`
int pop() {
data = next->data;
auto tmp = next;
next = next->next;
tmp->next = nullptr;
delete tmp;
return data;
}
`
Related
I'm trying to implement a linked list in C++. The list contains a pointer to a node type allocated on the heap
The code is as follow:
#include <memory>
template<typename T>
class node {
public:
node(T v) : value(v) {}
~node() = default;
T value;
node *next;
};
template<typename T, class Allocator = std::allocator<node<T>>>
class linked_list {
private:
node<T>* head;
Allocator alloc;
public:
linked_list() : head(nullptr) {}
~linked_list() {
for (auto start = head; start != nullptr; start = start->next) {
start->~node();
alloc.deallocate(start, 1);
}
}
void push_back(T value) {
node<T> *new_node = alloc.allocate(1);
new (new_node) node<T>(value);
if (head == nullptr) {
head = new_node;
return;
}
head->next = new_node;
head = new_node;
}
};
In main.cpp:
#include "linked_list.hpp"
int main() {
linked_list<int> a;
a.push_back(4);
a.push_back(5);
return 0;
}
When I ran it I got double free detected in cache T2.
What did I do wrong with the destructor ?
This is a common newbie error. You modified your loop control variable.
for (auto start = head; start != nullptr; start = start->next)
{
start->~node();
alloc.deallocate(start, 1);
}
You modified start (deleting the memory) in the for loop's body and then tried to dereference the pointer you just deleted in its continuation expression. BOOM! You are fortunate that the runtime library was smart enough to catch this and give you the "double free" error rather than, say, launch a nuclear missile.
This is one place a while loop is better than a for loop.
while (head)
{
auto to_del = head;
head = head->next;
to_del ->~node();
alloc.deallocate(to_del, 1);
}
I've left out a lot of commentary about your antiquated techniques because they don't relate to the problem you're having, but if you really want to substitute in a different kind of allocator you should look into using allocator_traits for allocation, construction, destruction, and deallocation of your elements.
There are other problems, such as push_back being completely wrong as to where it inserts the new node. Replacing head->next = new_node; with new_node->next = head; will at least keep your program from orphaning all of the new nodes.
I'm trying to implement a linked list using shared_ptr rather than raw pointers. The code :
#include <memory>
class NodeTest
{
private:
int v;
std::shared_ptr<NodeTest> next;
public:
NodeTest() { v = 0; };
NodeTest(unsigned int i) { v = i; }
~NodeTest() {};
void setNext(std::shared_ptr<NodeTest> & toSet) { next = toSet; }
};
std::shared_ptr<NodeTest> init()
{
std::shared_ptr<NodeTest> elt = std::shared_ptr<NodeTest>(new NodeTest());
std::shared_ptr<NodeTest> first = elt;
for (unsigned int i = 1; i < 5000; i++)
{
std::shared_ptr<NodeTest> next(new NodeTest(i));
elt->setNext(next);
elt = next;
}
return first;
}
void test_destroy()
{
std::shared_ptr<NodeTest> aList = init();
}
int main(int argc, char * argv[])
{
test_destroy();
}
This is generating a stackoverflow when leaving test_destroy() scope because of the call to aList destructor (RAII). To destroy aList, it calls the destructor of next and so on, which obviously ends up with a stackoverflow for a sufficiently large list.
I can't find any efficient way to fix this. The ideal case would be to delete the current NodeTest before moving to next deletion, right? How would you do such a thing?
Thanks in advance
Solution : You need to break the links between all nodes AND save a pointer to each node so that the destructor is not immediatly called upon breaking links. Example below using a vector.
~NodeTest()
{
std::vector<std::shared_ptr<NodeTest>> buffer;
std::shared_ptr<NodeTest> cursor = next;
while (cursor.use_count()!=0)
{
std::shared_ptr<NodeTest> temp = cursor->getNext();
cursor->setNext(std::shared_ptr<NodeTest>());
buffer.push_back(cursor);
cursor = temp;
}
next = std::shared_ptr<NodeTest>();
};
In this case you should manage nodes deleting manually because destructor calls destructor calls destructor .....
Take a look on the talk CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”
The destructor of NodeTest invokes the destructor of NodeTest::next which recursively calls another NodeTest destructor and so on until the stack is exhausted. Smart-pointers should not be used for linking nodes for this reason.
struct Node{
int value;
Node *next;
Node(int val) :value(val), next(nullptr){}
};
class Stack
{
public:
void push(int val);
int pop();
bool is_empty(){ return first == nullptr; }
private:
Node *first = nullptr;
};
int Stack::pop(){
int ret = first->value;
first = first->next;
return ret;
}
void Stack::push(int i){
if (is_empty()){
first = &Node(i);
return;
}
Node oldFirst = *first;
first = &Node(i);
first->next = &oldFirst;
}
Here is how I wrote the code, however, there is a problem that when I finished push() the pointer of first isn't point to the right object. I'm wondering how I can solve that problem.
The expression &Node(i) creates a temporary object and give you a pointer to it. And then the temporary object is immediately destructed, leaving you with a pointer to a non-existing object.
You need to use new to allocate a new object.
You have a similar problem with &oldFirst, which give you a pointer to a local variable, which will be destructed once the function returns. You need to use a pointer variable.
Code:
#include <iostream>
using namespace std;
class Node {
public:
Node *next;
int value;
Node(int value) {
this->next = nullptr;
this->value = value;
}
};
class LinkedList {
private:
Node *head;
Node *tail;
public:
LinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void addToEnd(int value) {
if(head == nullptr)
this->head = new Node(value);
else
this->tail->next = new Node(value);
this->tail = this->tail->next;
}
void print() {
for(Node *n = this->head; n != nullptr; n = n->next)
cout<<n->value<<" ";
cout<<endl;
}
};
int main() {
LinkedList *list = new LinkedList();
list->addToEnd(21);
list->addToEnd(25);
list->addToEnd(56);
list->addToEnd(24);
list->print();
return 0;
}
My problem is, when I am assigning an instance of Node to this->head, the program crashes. Is there different way of assigning an instance to a pointer that was initially nullptr?
This code structure works fine on Java, I came from Java, that is why I have difficulty on C++'s pointers.
EDIT
I pasted the right code now, I'm sure. Sorry.
Ok, I have solved the problem. So, the problem is not about allocating an object to a class member, but, the problem is accessing a nullptr member: this->tail.
I edited this method, and the program now runs the way I wanted.
void addToEnd(int value) {
Node *n = new Node(value);
if(head == nullptr)
this->head = n;
else
this->tail->next = n;
this->tail = n;
}
Thanks for your help people, this question is now SOLVED. :)
I don't know about "it crashes", but the following line is not valid:
this->head = Node(value);
head is a pointer-to-Node but you're trying to assign a Node to it. Even if this automatically took the address of the temporary you created on the RHS (which it doesn't), you'd have a pointer to a local variable that doesn't exist for very long.
You should be getting a compilation error for that.
You'd have to use new to create a new object dynamically — be sure to write code to free that memory later!
You're similarly messing up dynamic memory allocation in main, where you have a needless memory leak. LinkedList list; will do fine, there.
You need to allocate memory for your Node instances. The quickest way is to call new Node(value) wherever you call Node(value). However if I were you I'd consider using shared_ptr<Node> rather than plain pointers.
I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)