Im trying to make a copy of an object, which is a circular queue. My Enqueue and Dequeue work correctly, but whenever I do this, I get a runtime error.
CQUEUE j = k;
The output window says that my copy constructor is recursive on all control paths? Can someone help me figure out what I am doing wrong please? Here is my copy constructor, along with the overloaded assignment operator.
CQUEUE::CQUEUE(const CQUEUE& original)
{
(*this) = original;
}
void CQUEUE::operator=(CQUEUE w)
{
qnode *p = w.front;
(*this).front = new qnode;
(*this).back = front;
while(p -> next != w.back)
{
back -> num = p -> num;
p = p -> next;
back -> next = new qnode;
back = back -> next;
}
back -> num = p -> num;
p = p -> next;
back -> next = new qnode;
back = back -> next;
back -> num = p -> num;
back -> next = front;
front -> prev = back;
}
(*this) = original;
The compiler is making this line call the copy constructor instead of your = operator, because your = operator currently takes a non-const, by-value CQUEUE. Instead, your = operator should look like this:
void CQUEUE::operator=(const CQUEUE& w)
Then your copy constructor will call your operator = instead. Alternatively, make it more explicit:
CQUEUE::CQUEUE(const CQUEUE& original)
{
Copy(original);
}
void CQUEUE::operator=(const CQUEUE& w)
{
Copy(w);
}
void CQUEUE::Copy(const CQUEUE& other)
{
// All your copy code here
}
EDIT: Yes, you're correct, you still do need a copy constructor.
Change the assignment operator function to and be careful about self-assignment
void CQUEUE::operator=(const CQUEUE& w)
{
if (this == &w)
return *this;
//Paste your code
}
You're doing it backward, somewhat.
In general, the assignment operator is more complex than the copy constructor because it needs to properly dispose of the held resources on top of moving to the new value.
It is normally easier to compose a complex system out of simple parts rather than create a do-it-all part and express simple systems on top of it. In your context, it means than it is easier to create an assignment operator from a copy constructor.
Therefore, just write the copy constructor fully:
CQUEUE(CQUEUE const& c) { ... }
Then write a routine to swap (exchange the contents) of two CQUEUE instances:
void swap(CQUEUE& c) {
using std::swap;
swap(front, c.front);
swap(back, c.back);
}
And finally, build the assignment operator out of them:
CQUEUE& operator=(CQUEUE c) { // copy
this->swap(c);
return *this;
}
This idiom is known as copy-and-swap (yes, very creative!).
Note: bonus note, if you have a move constructor, then it becomes a move-and-swap for free.
Related
I am still somewhat new at c++, and I am a little confused about this.
Say we have struct struct_x that uses raw pointers as attributes. Should the raw pointers then be deleted in the copy assignment operator, when they are already allocated? Or should you just assign the new pointee to the pointer?
(I am aware that it is advised to use smart/unique/shared pointers).
Code example:
struct struct_x {
public:
// Some attributes.
char* m_arr nullptr;
size_t* m_len = nullptr;
size_t* m_alloc_len = nullptr;
// Default constructor.
struct_x() {
m_len = new size_t(0);
m_alloc_len = new size_t(0);
}
// Copy constructor.
// Treat "struct_x" as a unique pointer for this example.
struct_x(const struct_x& x) {
// Assign.
m_arr = new char[*x.m_alloc_len + 1];
memcpy(m_arr, x.m_arr,*x.m_len);
m_len = new size_t(*x.m_len);
m_alloc_len = new size_t(*x.m_alloc_len);
}
// Copy assignment operator.
void operator =(const struct_x& x) {
//
//
// OVER HERE
//
// Should the pointers be deleted when they are already allocated?
// Like:
if (m_arr != nullptr) { delete[] m_arr; }
if (m_len != nullptr) { delete m_len; }
if (m_alloc_len != nullptr) { delete m_alloc_len; }
// Or not?
// Assign.
...
}
}
Second question:
Do I need to delete the old m_arr after using memmove?
// Resize.
void resize(const len_t& req_len) {
using T = char; // only for this example.
if (req_len > m_alloc_len) {
if (m_alloc_len == 0) { m_alloc_len = req_len; }
m_alloc_len *= 16;
T* l_arr = new T [m_alloc_len + 1];
memmove(l_arr, m_arr, m_len);
// if (m_arr != nullptr && m_arr) { delete [] m_arr; } // Do i need to delete here, no right?
m_arr = l_arr;
}
}
If you are implementing a string-like class as an exercise, then m_len and m_alloc_len should not be pointers at all. Only m_arr should be a pointer. If you are not doing an exercise, you should be using std::string or perhaps std::vector<char>.
Having said that...
It is perfectly fine and necessary to delete owning raw pointers in assignment operators of resource-managing classes.
There is a caveat though. The assignment operator should be protected against self-assignment. If you do
my_object = my_object;
then without such protection your program will access deleted memory area. You want this:
void operator =(const struct_x& x) {
if (this != &x) {
// contents of your assignment operator
}
}
my_object = my_object is an unlikely assignment to appear in a program, but such things can and do happen, especially if there is indirection involved. Say when doing a[i] = a[j], it is perfectly reasonable to have i == j.
There are other (better) ways to protect against self-assignment. You will encounter them in due course. You probably need to learn about move semantics first.before
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;
}
I'm trying to implement a Singly linked list class in C++. I've overloaded the assignment operator to clone the list. The cloning itself seems to work fine, but the program crashes during deletion of the cloned list, which leads me to suspect if something's wrong during the copy procedure.
Any help is highly appreciated.
Here's the code for the overloaded = operator:
DLList& DLList::operator=(const DLList& iList)
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
return *this;
}
Here's the code for the push operation:
void DLList::push(int data)
{
Node *n = new Node;
n->data = data;
n->next = NULL;
//n->random = NULL;
n->next = _head;
_head = n;
//cout << "_head" <<_head->data<< "head->next" << (_head->next ? _head->next->data : 0)<<endl;
}
Here's the main code (where the crash happens) :
DLList *d = new DLList();
d->push(10);
d->push(20);
d->push(30);
d->push(40);
d->setRandom();
d->display("Original list"); // Displays the original list fine
DLList *d1 = new DLList();
d1 = d;
d1->display("Cloned list"); //Displays the cloned list fine
delete d; // works fine
delete d1; // Crashes here due to segmentation fault, invalid pointer access during delete called as part of destructor)
Code for destructor (if it helps):
~DLList()
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
}
you are not using the assignment operator actually! You are just copying the pointer to the other pointer.
Debugging your code (or just add traces) would have showed that
you were not calling your copy code
the addresses of d and d1 are the same
So when you delete the second list you delete the same address twice.
You don't really need new here:
DLList d;
d.push(10);
DLList d1 = d; // assignment is REALLY called
d1.display("Cloned list");
the objects will be deleted when you go out of scope of your variables
If you want to test in your context, keeping the new, change
d1 = d;
by
*d1 = *d;
to activate assignment operator.
Another advice: factorize your copy code so it is shared between assignment operator and copy constructor, and the deletion code should be shared between destructor and assignment operator (to avoid memory leaks when assigning twice): Not tested, don't flame me if it doesn't compile, just tell me I'll fix it, I'm already overanswering here :)
DLList& DLList::operator=(const DLList& iList)
{
destroy(); // or you'll get memory leaks if assignment done twice
copy(iList);
return *this;
}
DLList& DLList::DLList(const DLList& iList)
{
_head = NULL; // set _head to NULL in all your constructors!!
copy(iList);
}
~DLList()
{
destroy();
}
void DLList::copy(const DLList& iList) // should be private
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
}
void DLList::destroy() // private
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
_head = NULL; // calling destroy twice is harmless
}
d1 = d; is NOT copying DLList. Instead, you just make d1 point to the list that d pointing to. So, both d1 and d are pointing to the same list. At the end of your program, you will delete the list twice, and make your program crash.
If you wish to use the assignment operator, you need to dereference your pointers. See here:
DLList *d1 = new DLList();
d1 = d; // <------------- This line
d1->display("Cloned list"); //Displays the cloned list fine
On the highlighted line, you're setting the pointer d1 to point to the same location as d. This means that when you call delete at the end of your code, you're trying to delete the same object (d in this case) twice.
To fix your code, you should dereference your pointers:
DLList *d1 = new DLList();
*d1 = *d; // <------------- Note the dereference applied to BOTH lists.
d1->display("Cloned list"); //Displays the cloned list fine
Alternatively, you should avoid using pointers entirely if you can. For your trivial example you could simply create your objects directly.
Your problem is the statement
d1 = d;
which does a pointer assignment, and makes d1 point to the same object as d. The subsequent delete statements cause the same object (*d) to be released twice. That is undefined behaviour (of which one symptom is a crash like you describe).
The above also does not invoke DLLists copy constructor. If that is your intent, you need to do
*d1 = *d;
which makes the object pointed to by d1 a copy of the one pointed to by d. The two delete statements are also appropriate in this case.
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;
}
}
I haven't been able to find a good answer to this question.
I'm working on a C++ program and I'm trying to implement a function named copy which takes a reference to another object as an argument. Then, it returns a deep copy of this object.
Some background on my project: the Scene class contains a dynamic array (called "Images") of pointers to either NULL or an instance of the Image class, which is not shown here - but works as it should (it inherits all of its methods from a third party library, EasyBMP)
The reason I'm doing this is to avoid duplicating code in two places, but it's very possible that I'm taking the wrong approach.
I call this function in my assignment operator:
Scene const & Scene::operator=(Scene const & source)
{
if (this != &source) {
clear();
copy(source);
}
return *this;
}
And my copy constructor:
Scene::Scene(Scene const & source)
{
copy(source);
}
Finally, my copy() method looks like this:
Scene const & Scene::copy(Scene const & source)
{
Scene res(source.Max);
for (int i=0; i<res.Max; i++)
{
delete res.Images[i];
if (source.Images[i] != NULL)
res.Images[i] = new Image(*(source.Images[i]));
else
res.Images[i] = NULL;
}
return res;
}
Currently, it does NOT work. One problem I can see is that I'm trying to return a variable that goes out of scope as soon as the copy function ends. I tried returning a reference before, but the compiler threw errors and this wouldn't help with the scope issue anyways.
But I'm not even sure that my logic is right, i.e. can you even do something like this in a constructor? Or should I just explicitly write out the code in the copy constructor and assignment operator (without implementing the helper method copy)?
I'm very new to C++ and pointers, so any guidance would be much appreciated.
There's a way easier and more idiomatic way to do what you want: the copy-and-swap idiom.
// N.B. Not tested, but shows the basic structure of the copy-and-swap idiom.
class Scene
{
public:
Scene(int)
{
// Initialize a pointer array of Images
}
~Scene()
{
// Get rid of our pointer array of Images
}
// Copy constructor
// N.B. Not exception safe!
Scene(const Scene& rhs) : imgPtrArray(new Image*[rhs.max])
{
// Perform deep copy of rhs
for (int i=0; i < rhs.max; ++i)
{
if (rhs.imgPtrArray[i] != 0)
imgPtrArray[i] = new Image(*(rhs.imgPtrArray[i]));
else
imgPtrArray[i] = 0;
}
}
// Copy assignment constructor
// When this is called, a temporary copy of Scene called rhs will be made.
// The above copy constructor will then be called. We then swap the
// members so that this Scene will have the copy and the temporary
// will destroy what we had.
Scene& operator=(Scene rhs)
{
swap(rhs);
return *this;
}
void swap(Scene& rhs)
{
// You can also use std::swap() on imgPtrArray
// and max.
Images** temp = imgPtrArray;
imgPtrArray = rhs.imgPtrArray;
rhs.imgPtrArray = temp;
int maxTemp = max;
max = rhs.max;
rhs.max = maxTemp;
}
private:
Images** imgPtrArray;
int max;
};
That being said, I highly recommend that you pick up a good introductory C++ book, which will cover the basics of implementing the copy constructor and copy assignment operators correctly.
Scene const & Scene::operator=(Scene const & source);
overloaded assignment operator copies the content of this to the argument received source. For copy there is no need to return any thing or to create a local object. Just make a member wise copy from this to source.
void Scene::copy(Scene const & source){
// Member wise copy from this to source
}
Rule of three should be helpful to better understand more about these.