I was trying to use the overload operator method to copy the entries of one queue into another, but I am going wrong with my function. I don't know how else to access the values of the queue "original" any other way than what I have below:
struct Node
{
int item;
Node* next;
};
class Queue
{
public:
// Extra code here
void operator = (const Queue &original);
protected:
Node *front, *end;
};
void Queue::operator=(const Queue &original)
{
//THIS IS WHERE IM GOING WRONG
while(original.front->next != NULL) {
front->item = original.front->item;
front->next = new Node;
front = front->next;
original.front = original.front->next;
}
}
Do you have a functional copy constructor? If so, I'd implement your assignment operator in terms of your copy constructor like so:
#include <algorithm> // <utility> for C++11
void Queue::operator=(const Queue &other)
{
// Assumes your only field is the "front" pointer.
Queue tmp(other); // May throw.
std::swap(front, tmp.front); // Will not throw.
}
The idea is that you perform any operations that can throw an exception (like your call to operator new()) on the side in a temporary object that will clean up resources, and then "commit" your changes by swapping the contents in a non-throwing operation so that the state of your Queue is sane even if an exception is thrown in during the construction of tmp. Pointer assignment is guaranteed not to throw, which is why the call to std::swap() is non-throwing in this case. Upon leaving the scope of your assignment operator tmp's destructor should clean up your old link list since its front was swapped with your old front.
See GotW #59 for details about this "copy-to-temporary-and-swap" idiom, and how it relates to the strong exception safety guarantee.
void Queue::operator=(const Queue &original)
{
Node* tmp = original.front;
//THIS IS WHERE IM GOING WRONG
while(tmp->next != NULL) {
front->item = tmp->item;
front->next = new Node;
front = front->next;
tmp = tmp->next;
}
}
Related
I have a problem with the application crashing at the line of code where if(!head) is being referenced inside the function: insertNode(). head and tail are class members of type node*. It looks like, I am missing something in the way the class members: head, tail are initialized..
This is the runtime error: "Unhandled exception at 0x00245246 in SLinkedlist_array.exe: 0xC0000005: Access violation reading location 0x00000000."
slinkedlist.h:
typedef struct node
{
int value;
struct node* next;
} node;
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail;
};
slinkedlist.cpp:
bool slinkedlist::insertNode(int value, int aftNodeVal)
{
int toinsertval = value;
int searchkey = aftNodeVal;
bool retval = false;
// If it's a new linked list
if(!head) // THIS IS WHERE THE APPLICATION CRASHES!
{
node* head = new node;
head->value = toinsertval;
head->next = NULL;
return true;
}
else //It's not a new list
{
while(head->next != NULL)
{
//some more code here...
}
}
return retval;
}
void slinkedlist::displayList()
{
while(!head)
{
do
{
cout << head->value << " " ;
head = head->next;
}
while(head->next != NULL);
}
//return void;
}
main.cpp:
int main()
{
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
while(1);
}`
The answer is simple: you have null-pointer dereference here:
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
That's what exactly the system tells to you: "Access violation reading location 0x00000000"
Solution can be like:
slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;
Or like this (why not to use just an object on the stack?):
slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();
Or more C++ way (if you NEED a pointer):
auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
slinkedlist *s1 = NULL;
defines a pointer to a slinkedlist and DOES initialize it Unfortunately it initializes it to NULL, a safe parking address where (usually) no object are allowed to exist. For the vast majority of CPUs (every CPU I've ever worked on) accessing this dead zone around NULL will crash the program, making it much easier to detect bugs.
There is no need for a pointer here. If you don't need pointer, don't use one. Your life will be much easier.
int main()
{
slinkedlist s1; // default initializes
s1.insertNode(4, -1);
s1.displayList();
while(1); // rethink this. If you want to hold a program open to see the output
// while debugging, place a breakpoint in the debugger.
}
Default initializing of s1 alone will not help you because it will do the absolute minimum work to initialize its member variables, and in the case of a pointer the minimum work is to do nothing and leave head and tail uninitialized and pointing (sort of. tail is NOT a pointer) to an indeterminate location. Because you aren't also asking about the compiler error you should get from assigning NULL to tail, the program is clearly not initializing tail and I'll assume the slinkedlist constructor doesn't do much.
Side note: If you have a constructor or destructor that don't do anything (and don't need to do anything) leave them out and let the compiler generate the appropriate code. Code that does not exist (and doesn't need to exist) has no bugs.
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail; // the * only applies to head.
};
could be
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head = nullptr;
node* tail = nullptr;
};
if you are compiling to recent (2011 or newer) C++ Standards. You won't need a constructor, the work is done for you with the default assignments. You will still need a destructor along with a copy constructor and an assignment operator to satisfy The Rule of Three.
In older C++ Standards you need to make the constructor smarter
class slinkedlist
{
public:
slinkedlist(): head(NULL), tail(NULL)
{
}
//dtor, insertNode(int, int), displayList()
private:
node* head; // I recommend splitting the definitions up. It makes the code easier
// to read and makes it harder to make mistakes.
node* tail;
};
You will still need a destructor, a copy constructor, and an assignment operator.
Note that this also applies to node. If you dynamically allocate a node and do not explicitly set next to a value, you won't know where next points, and all of the tests like
while(head->next != NULL)
will fail horribly.
I'm currently having a problem copying the contents from one list to another. The values all appear as 0 when compiled. I thought that there might be something wrong when overloading the assignment operator as the copy constructor is using its code.
Copy Constructor
ListOfDoubles::ListOfDoubles(const ListOfDoubles&e):head(NULL) {
if (this != &e) {
*this = e;
}
}
Overloaded operator=
const ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles
&doubleslist)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode* orgPtr = doubleslist.head;
if (this != &doubleslist)
{
while (head != NULL)
{
ListOfDoubles::~ListOfDoubles();
}
while (orgPtr != NULL)
{
if (head == NULL)
{
head = cpyPtr = new DoubleListNode(orgPtr->data);
}
else
{
cpyPtr->next = new DoubleListNode(orgPtr->data);
cpyPtr = cpyPtr->next;
}
orgPtr = orgPtr->next;
}
}
return *this;
}
General-purpose copy logic looks something like:
DoubleListNode * from = source.head; // copying from
DoubleListNode ** to = &head; // pointer to where we want to copy to
while (from != nullptr) // keep going until end of list. You did mark
// the end of the list, didn't you?
{
*to = new node(*from); //copy construct a new node around from and store it at to
to = &(*to)->next; // advance to
from = from.next; // advance from
}
*to = nullptr; // all done. Terminate list.
The real magic is going on up here at the double pointer: DoubleListNode ** to By having a pointer to a pointer, we don't care whether we're pointing at head, another node's next or what have you. It's just another node, so there are no special cases to cover.
You can do the above in both the copy constructor and assignment operator, though you are better off not repeating yourself and putting it in a function called by the copy constructor and assignment operator. Note that there are different assumptions about pre-existing data in the copy constructor (eg, list will be empty) and the assignment operator (eg, list may not be empty, so clear it and free all of the nodes before you begin) that need to be taken into account.
The primary alternative, as discussed in the comments above, is to use the Copy and Swap Idiom. For this, the above copy loop only exists in the copy constructor.
The input parameter of a copy constructor will never be the object being constructed, so checking for this != &e in the copy constructor is redundant.
Also, manually calling a destructor directly is illegal unless the memory was allocated with placement-new, which you are not using. You need to use delete to destroy your node instances.
Typically, you shouldn't implement the copy constructor in terms of operator=, you should do it the other way around. Let the copy constructor do its job of copying the source values, and then have operator= make a copy of the source list and take ownership of the copied data. This is commonly known as the "copy and swap" idiom.
Try this instead:
ListOfDoubles::ListOfDoubles()
: head(NULL)
{
}
ListOfDoubles::ListOfDoubles(const ListOfDoubles &e)
: head(NULL)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode *prevPtr = NULL;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
cpyPtr = new DoubleListNode(orgPtr->data);
if (!head)
head = cpyPtr;
if (prevPtr)
prevPtr->next = cpyPtr;
prevPtr = cpyPtr;
orgPtr = orgPtr->next;
}
/* alternatively:
DoubleListNode **cpyPtr = &head;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
*cpyPtr = new DoubleListNode(orgPtr->data);
cpyPtr = &((*cpyPtr)->next);
orgPtr = orgPtr->next;
}
*cpyPtr = NULL;
*/
}
ListOfDoubles::~ListOfDoubles()
{
DoubleListNode *orgPtr = head;
DoubleListNode *nextPtr;
while (orgPtr)
{
nextPtr = orgPtr->next;
delete orgPtr;
orgPtr = nextPtr;
}
}
ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles &doubleslist)
{
if (this != &doubleslist)
{
ListOfDouble tmp(doubleslist);
std::swap(head, tmp.head);
}
return *this;
}
Hello I am trying to use pointers and learning the basics on unique pointers in C++. Below is my code I have commented the line of code in main function. to debug the problem However, I am unable to do so. What am I missing ? Is my move() in the insertNode() incorrect ? The error I get is below the code :
#include<memory>
#include<iostream>
struct node{
int data;
std::unique_ptr<node> next;
};
void print(std::unique_ptr<node>head){
while (head)
std::cout << head->data<<std::endl;
}
std::unique_ptr<node> insertNode(std::unique_ptr<node>head, int value){
node newNode;
newNode.data = value;
//head is empty
if (!head){
return std::make_unique<node>(newNode);
}
else{
//head points to an existing list
newNode.next = move(head->next);
return std::make_unique<node>(newNode);
}
}
auto main() -> int
{
//std::unique_ptr<node>head;
//for (int i = 1; i < 10; i++){
// //head = insertNode(head, i);
//}
}
ERROR
std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Aside from other small problems, the main issue is this line:
return std::make_unique<node>(newNode);
You are trying to construct a unique pointer to a new node, passing newNode to the copy constructor of node. However, the copy constructor of node is deleted, since node contains a non-copyable type (i.e. std::unique_ptr<node>).
You should pass a std::move(newNode) instead, but this is problematic since you create the node on the stack and it will be destroyed at the exit from the function.
Using a std::unique_ptr here is a bad idea in my opinion, since, for example, to print the list (or insert into the list), you need to std::move the head (so you lose it) and so on. I think you're much better off with a std::shared_ptr.
I was having the same problem and indeed using a shared_ptr works.
Using the smart pointer as an argument in the function copies the pointer (not the data it points to), and this causes the unique_ptr to reset and delete the data it was previously pointing at- hence we get that "attempting to reference a deleted function" error. If you use a shared_ptr this will simply increment the reference count and de-increment it once you are out of the scope of that function.
The comments in the answers above suggest that using a shared_ptr is baseless. These answers were written before the C++17 standard and it is my understanding that we should be using the most updated versions of the language, hence the shared_ptr is appropriate here.
I don't know why we have to expose node type to user in any case. Whole thingamajig of C++ is to write more code in order to write less code later, as one of my tutors said.
We would like to encapsulate everything and leave no head or tail (pun intended) of node to user. Very simplistic interface would look like:
struct list
{
private:
struct node {
int data;
std::unique_ptr<node> next;
node(int data) : data{data}, next{nullptr} {}
};
std::unique_ptr<node> head;
public:
list() : head{nullptr} {};
void push(int data);
int pop();
~list(); // do we need this?
};
The implementation does something what Ben Voigt mentioned:
void list::push(int data)
{
auto temp{std::make_unique<node>(data)};
if(head)
{
temp->next = std::move(head);
head = std::move(temp);
} else
{
head = std::move(temp);
}
}
int list::pop()
{
if(head == nullptr) {
return 0; /* Return some default. */
/* Or do unthinkable things to user. Throw things at him or throw exception. */
}
auto temp = std::move(head);
head = std::move(temp->next);
return temp->data;
}
We actually need a destructor which would NOT be recursive if list will be really large. Our stack may explode because node's destructor would call unique_ptr's destructor then would call managed node's destructor, which would call unique_ptr's destructor... ad nauseatum.
void list::clear() { while(head) head = std::move(head->next); }
list::~list() { clear(); }
After that default destructor would ping unique_ptr destructor only once for head, no recursive iterations.
If we want to iterate through list without popping node, we'd use get() within some method designed to address that task.
Node *head = list.head.get();
/* ... */
head = head->next.get();
get() return raw pointer without breaking management.
How about this example, in addition to the sample code, he also mentioned some principles:
when you need to "assign" -- use std::move and when you need to just traverse, use get()
I'm writing some C++ code for a simple "Node" class. This is basically a class used to manage a linear linked list. I normally perform this with a struct but I'm trying get a better handle of OOP and classes. What I've got thus far for the Node class is (note: the String class is my version (trimmed down) of a typical "string" class, it implements a copy constructor, assignment overload, destructor, etc. In testing it has worked great and seems completely self contained):
class Node {
public:
//Constructor
//-----------
Node() : next_(0) {} //inline (String constructor called)
//Destructor
//----------
~Node();
//Copy Constructor
//----------------
Node(const Node &);
//Operator Overload: =
//---------------------
//In conjunction with copy constructor. Protects Class.
Node & operator=(const Node &);
private:
String relatedEntry_;
Node * next_;
};
Creating one instance works fine (ie. Node node;) but when I create an instance that calls the Copy Constructor I end up with segfaults at the very end of my program, as it's cleaning up. The difference between using a struct for a linked list vs a class plays tricks with me a little and I think I'm missing something key here. Here is the implementation for the Default Constructor, Copy Constructor, and Overloaded Assignment Operator:
//Constructor inlined
//Destructor
Node::~Node()
{
Node * curr = next_;
while (curr) //cycle through LL and delete nodes
{
Node * temp = curr; //hold onto current
curr = curr->next_; //increment one
delete temp; //delete former current
}
}
//Copy Constructor
Node::Node(const Node & cp)
{
std::cout << "in CopyCon" << std::endl;
relatedEntry_ = cp.relatedEntry_; //calls String class copy constructor/assignment overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr) //copies related entry structure
{
Node * oldNext = next_;
next_ = new Node;
next_->next_ = oldNext; //'next' field (assign prior)
next_->relatedEntry_ = curr->relatedEntry_; //String class copy
curr = curr->next_; //increment
}
}
//OO: =
Node & Node::operator=(const Node & cp)
{
std::cout << "in OO: =" << std::endl;
if (this == &cp)
return *this; //self assignment
delete next_; //delete LL
relatedEntry_ = cp.relatedEntry_; //String Class Assignment Overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr)
{
Node * oldNext = next_; //hold onto old
next_ = new Node;
next_->next_ = oldNext; //set next to old
next_->relatedEntry_ = curr->relatedEntry_; //set this string to cp string
curr = curr->next_; //increment
}
return *this;
}
Note that using the Overloaded Assignment Function seems to work fine (no segfaults) even though it's virtually the same code... I'm assuming it has to do with the fact that both objects are already initialized before the assignment takes place?
//This seems to work ok
Node node1;
Node node2;
node2 = node1;
I've been at this bug for a couple of hours and I have got to get some rest. I'd really appreciate any insight into this. Thanks.
In the copy constructor loop, you have this line:
Node * oldNext = next_;
However, in the first round in the loop the value of next_ can by, well, anything and most likely not NULL. This means that the last node will a have a non-null pointer.
Initialize it to NULL before the loop and it should work.
You have the concepts of a List and a Node mixed up. You should write a List class which manages a sequence of Nodes. Your Node destructor is more or less how your List destructor should look, Node itself doesn't need a destructor.
What is specifically going wrong is that your Node destructor recursively calls itself when you write delete temp; this deletes the rest of the sequence of nodes but then your Node destructor loops around and tries to delete them again.
I'm writing a program as an assignment for school and I though I had worked out all the bugs until I decided to call my copy constructor. The program is interactive (CLI) which basically has two moduals: a .h and .cpp file for the LList class and a .h and .cpp file for the structure of the program and also a 3rd cpp file just for main(). It is suppose to be a program for a hydropower engineering company (fake company) in which the LList nodes hold data for their annual water flow in a river(year and flow). Here is some insight on the class:
//list.h
struct ListItem {
int year;
double flow;
};
struct Node {
ListItem item;
Node *next;
};
class FlowList {
public:
FlowList();
// PROMISES: Creates empty list
FlowList(const FlowList& source);
// REQUIRES: source refers to an existing List object
// PROMISES: create the copy of source
~FlowList();
// PROMISES: Destroys an existing list.
FlowList& operator =(const FlowList& rhs);
// REQUIRES: rhs refers to an existing FlowList object
// PROMISES: the left hand side object becomes the copy of rhs
//....Other member functions
private:
// always points to the first node in the list.
Node *headM;
// Initially is set to NULL, but it may point to any node.
Node *cursorM;
//For node manipulation within interactive CLI
void copy(const FlowList& source);
void destroy();
I belive the memory leak or collision is taking place somewhere within the copy function but cant pin point where.
//list.cpp
FlowList::FlowList() : headM(0), cursorM(0) {}
FlowList::FlowList(const FlowList& source)
{
copy(source);
}
FlowList::~FlowList()
{
destroy();
}
FlowList& FlowList::operator =(const FlowList& rhs)
{
if (this != &rhs)
{
destroy();
copy(rhs);
}
return (*this);
}
//...more function definitions
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
Node* new_node = new Node;
assert(new_node);
new_node->item.year = source.headM->item.year;
new_node->item.flow = source.headM->item.flow;
new_node->next = NULL;
headM = new_node;
Node* thisptr = new_node;
for(Node* srcptr = source.headM->next; srcptr != NULL; srcptr = srcptr->next)
{
new_node = new Node;
assert(new_node);
new_node->item.year = srcptr->item.year;
new_node->item.flow = srcptr->item.flow;
new_node->next = NULL;
thisptr->next = new_node;
thisptr = thisptr->next;
}
}
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
while (ptr != NULL)
{
delete ptr;
ptr = post;
if (post)
post = ptr->next;
}
headM = NULL;
}
The program works fine if I create a FlowList object, fill it with data from a .dat file; i can then manipulate the data within the program (display, perform calculations, add to the list, remove from list and save data to file) but program crashes (segmentation fault) if I create another FlowList object (within main.cpp).
Any help would be really appreciated.
The initial thing I spot is that it looks like your destroy() function will always segmentation fault if the list is empty:
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
//...
}
If the list is empty, headM is NULL and then you're trying to do headM->next which will always produce a segmentation fault in that case.
I think you might also have a memory leak in your copy constructor if you pass in an empty list. If you look at this code:
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
//...
}
What if the current list contained 20 items and source is an empty list? You set the current list's headM and cursorM to NULL, but you never call delete on any of the nodes in the current list that you originally used new to create. You probably want to work your destroy() function somewhere into your copy constructor too (you did it for the operator= function).
The last thing I noticed is that you don't initialize cursorM for a non-empty list in your copy() function (#Akusete pointed that out as well). I think I'd recommend that at the beginning of your copy constructor, just initialize cursorM and headM to NULL just to cover your bases.
It looks like you're really close, I think you just really need to think through the boundary case of dealing with empty lists (both on the LHS and RHS) and you'll probably find most of these bugs. Good luck!