Overloading copy assignment operator - c++

I have recently been learning overloaded operator and soon came to overloaded copy operator. I tried some example but couldn't really understand the format and how it function. Well, it would be helpful if you could explain me the code in easier terms because since I'm a beginner in c++. Anyway here is my code:
#include <iostream>
using namespace std;
class Point{
private:
int* lobster;
public:
Point(const int somelobster){
lobster = new int;
*lobster = somelobster;
}
//deep copy
Point(const Point& cpy){ //copy of somelobster(just to make sure that it does not do shallow copy)
lobster = new int;
*lobster = *cpy.lobster;
}
//assingment operator
Point& operator=(const Point& cpy){ //used to copy value
lobster = new int; //same thing as the original overloaded constructor
*lobster = *cpy.lobster; //making sure that it does not makes a shallow copy when assigning value
return *this;
}
void display_ma_lobster(){ //display nunber
cout << "The number you stored is: " << *lobster << endl;
}
~Point(){ //deallocating memory
cout << "Deallocating memory" << endl;
delete lobster;
}
};
int main(){
Point pnt(125);
cout << "pnt: ";
pnt.display_ma_lobster();
cout << "assigning pnt value to tnp" << endl;
Point tnp(225);
tnp = pnt;
tnp.display_ma_lobster();
return 0;
}
but the main part which really need explanation are:
//deep copy
Point(const Point& cpy){ //copy of somelobster(just to make sure that it does not do shallow copy)
lobster = new int;
*lobster = *cpy.lobster;
}
//assingment operator
Point& operator=(const Point& cpy){ //used to copy value
lobster = new int; //same thing as the original overloaded constructor
*lobster = *cpy.lobster; //making sure that it does not makes a shallow copy when assigning value
return *this;
}
thank you for your time

The copy assignment operator may use existing resources already owned by the object. It is not like a constructor. (Your copy constructor is correct.)
//assingment operator
Point& operator=(const Point& cpy){ //used to copy value
// Do not allocate anything here.
// If you were to allocate something, that would require deallocating yer shit too.
*crap = *cpy.crap; //making sure that it does not makes a shallow copy when assigning value
return *this;
}

A good read on this topic is: What is the copy-and-swap idiom?
Your object contains allocated memory, so each time you copy your object, you also need to perform a new memory allocation, and copy the contents of your allocation. That is why you need those things in the copy constructor. The copy constructor is automatically called when the compiler tries to copy your object, such as across a function call, of if it is placed into a container.
The assignment operator is flawed, because it needs to do a bit more or a bit less. It is used in
tnp = pnt;
Because it is handling assigning one object to another, it needs to either use the existing allocated memory, or handle the deallocation of memory in the old tnp object before the pnt memory is copied in.

Related

Denstructor deletes a member which is already replaced?

I am pretty new to the C++ world...
I have a question about destructors in C++.
If there is a class like:
class TestClass {
public:
double *array;
}
When I put a pointer of one array to *array and put again another and delete Testclass instance, then I can no longer access the older one?
It becomes an error:
int main() {
TestClass tc;
tc.array = new double[10];
double *array2 = tc.array;
tc.array[3]=9;
tc.array = new double[10];
delete &tc; // <------------------- this one.
std::cout<<array2[3]<<std::endl;
// std::cout<<tc.array[3]<<array2[3]<<std::endl;
}
If there is no delete &tc and activate the commentline (the last line),
'09' shows up, (tc.array[3] != array2[3] => tc.array != array2)
which does not mean tc.arrray is not the one in *array2 ??
What is wrong?
The tc is a function-scoped variable (allocated on the stack). It's not allocated with new. You can't delete it. it will be freed automatically when the function return
Dealing with raw pointers is somewhat tricky and your class would probably benefit from using a std::vector<double> instead of a raw pointer. Another choice could be a std::unique_ptr<double[]> that handles deleting the pointer for you.
That said, if you want to try it out, you should know when and what to delete.
tc is an automatic variable. You didn't create tc using new so you should not delete it. It will be destroyed when it goes out of scope - when the program leaves the block in which tc was created.
You haven't defined a destructor for TestClass so the memory to which array points will still be allocated even after tc is destroyed. The destructor would typically look like this:
~TestClass() {
delete[] array;
}
You also assign directly to tcs internal pointer, which is dangerous. You should have just as many delete[] as you have new[]s, which is not the case in your program, so it'll leak. You should typically hide the internal pointer so it can't be reassigned without the object owning it having control.
For manual memory management to work properly, there are some member functions you should consider:
Copy constructor
Move constructor
Copy assignment operator
Move assignment operator
Destructor
You can read more about those here: The rule of three/five/zero
Here's an example of what your class could look like with the 5 member functions mentioned above plus a default constructor, a converting constructor taking a pointer as parameter and two subscript operators.
#include <iostream>
#include <utility> // std::move, std::swap, std::exchange
class TestClass {
public:
// default constructor
TestClass() :
array(nullptr) // member initializer
{
std::cout << "default ctor\n";
}
// converting constructor - refuse lvalue pointers since we want to make sure
// that we "own" the pointer
TestClass(double*&& p) : array(p) {
std::cout << "converting ctor " << p << "\n";
}
// copy constructing without knowledge about the size of the array isn't possible
TestClass(const TestClass&) = delete;
// move construction works though
TestClass(TestClass&& rhs) :
array(std::exchange(rhs.array, nullptr)) // steal pointer from rhs
{
std::cout << "move ctor\n";
}
// copy assignment without knowledge about the size of the array isn't possible
TestClass& operator=(const TestClass&) = delete;
// move assignment works though
TestClass& operator=(TestClass&& rhs) {
std::cout << "move assignment\n";
// swap pointers with rhs - let rhs delete[] our current pointer
std::swap(array, rhs.array);
return *this;
}
~TestClass() { // destructor
delete[] array;
}
// subscripting support
double& operator[](size_t idx) { return array[idx]; }
double operator[](size_t idx) const { return array[idx]; }
private: // hide your raw pointer from direct access
double* array;
};
void printer(const TestClass& tc, size_t idx) {
// use const version of operator[] in the class
std::cout << tc[idx] << "\n";
}
int main() {
TestClass tc; // default ctor
// use the converting constructor that creates a TestClass object from a pointer.
// It is then move assigned to tc
tc = new double[10];
tc[3] = 1; // use the non-const version of operator[] in the class
printer(tc, 3);
double* a = new double[10];
// tc = a; // this won't work since we don't accept lvalues in assignment
tc = std::move(a); // make an xvalue to allow the assignment. "a" should not be
// delete[]-ed after this since we granted tc the possibillity
// to take ownership the pointer.
tc[3] = 2;
printer(tc, 3);
}

Error Within Overloaded Assignment Operator Function and Copy Constructor

I am currently writing a program that creates a dynamically allocated circular array. For it, I have created a copy constructor and an assignment operator.
I am getting an error called "munmap_chunk(): invalid pointer", when I try to call my assignment operator for a second time. If I call it once, the error does not show. Am I writing my copy constructor and assignment operator properly? If there is any information needed I am happy to provide, thank you.
CircularDynamicArray(const CircularDynamicArray& source){
cout << "copy constructor called" << endl;
m_capacity = source.m_capacity;
m_size = source.m_size;
m_front = source.m_front;
m_rear = source.m_rear;
arr = new elmtype[source.m_capacity];
for(int i = 0; i < source.m_capacity; i++) {
arr[i] = source.arr[i];
}
}
//overloaded assignment operator
CircularDynamicArray &operator = (const CircularDynamicArray& source) {
cout << "Overloaded Assignment called" << endl;
//check for self assignment
if (this == &source) {
return *this;
}
m_capacity = source.m_capacity;
m_size = source.m_size;
m_front = source.m_front;
m_rear = source.m_rear;
delete[]arr;
for(int i = 0; i < source.m_capacity; i++) {
arr[i] = source.arr[i];
}
return *this;
}
Am I writing my copy constructor and assignment operator properly?
I will say that you are making more work for yourself than necessary when it comes to writing an assignment operator.
If you have written a copy constructor (which you have), and a destructor (which you didn't show, but let's assume you did), and both of these functions have no bugs, then the assignment operator can be implemented trivially using copy / swap.
In general, you should strive to write the copy constructor and destructor before writing the assignment operator, so that this "trick" of writing the assignment operator can be utilized. Here is an example:
#include <algorithm>
//...
CircularDynamicArray &operator=(const CircularDynamicArray& source)
{
if (this != &source)
{
CircularDynamicArray temp(source); // Create a copy of what we want
// get the temp's innards, and give temp our stuff
std::swap(temp.m_capacity, m_capacity);
std::swap(temp.m_size, m_size);
std::swap(temp.m_front, m_front);
std::swap(temp.m_rear, m_rear);
std::swap(temp.arr, arr);
} // goodbye temp
return *this;
}
No allocating memory, no delete[] calls, you don't even need a check for self-assignment (but done anyway, for efficiency purposes). The above is exception-safe also. Everything you need for an assignment operator to work, basically flawlessly.
Note that you need to swap all of the member variables -- don't forget any, as that will cause this to not work correctly.
All that is being done is that you're making a copy of the passed-in object, and swapping out the guts of the current object this with the copy. Then the copy dies off with your old information. This is why you need a working copy constructor (for the initial copying of the source to work), and a working destructor (so that the destruction of the temp works).

Why do we need to delete pointers inside copy assignment operator

I have seen several examples of copy assignment operator and could not understand why do we need to delete pointers inside copy assignment operator. For example if I have the following class
class MyClass
{
public:
MyClass(int a)
{
x = new int(a);
}
MyClass& operator=(const MyClass& pMyClass)
{
*x = *(pMyClass.x);
// ?????????
// delete x;
// x = new int(*(pMyClass.x));
}
~MyClass()
{
delete x;
}
private:
int* x;
}
What is wrong with *x = *(pMyClass.x) line? I am just copying object pointed by pMyClass.x why I need to delete and create it again?. Could anyone please give example when this code will cause memory leak?
So this is an example [extracted from Bjarne Stroustrup's "A tour of C++ (2nd edition)] of a copy assignment of a user defined vector class:
Vector& Vector::operator=(const Vector& a) // copy assignment
{
double∗ p = new double[a.sz];
for (int i=0; i!=a.sz; ++i)
p[i] = a.elem[i];
delete[] elem; // delete old elements
elem = p; // here elem is the vector's data holding member array
sz = a.sz;
return ∗this;
}
To understand why at line 6 we have the deletion operation:
delete[] elem; // delete old elements
we first need to first understand the distinction between copy constructor and copy assignment. In the first case (copy constructor) we create a completely new object, whereas in the second case (copy assignment, the one we're actually interested in) we already have an existing object into which we just want to copy the contents of another given object of the same type.
Given the fact that we already have an existing object, we first need to clear it's contents so that we are then able to copy the desired content from the object we intent to copy.
I hope that answers your question.
It is a valid code. But if instead of the pointer to a single object you will have a pointer to first element of an array and arrays may have different sizes then you need to delete the array that to reallocate it with the new size.
Nothing wrong with *x = *(pMyClass.x) when you copying value from one class instance to other. I think, in general, deleting an object (if it is not just int) can prevent usage of new object with new data if before operator= execution address stored in x was sent to some other part of program.

Heap Corruption error with Copy constructor and overloaded assignment operator

I am a student so I apologize up front for not using the correct forum protocols. I have searched for hours on this problem, none of my classmates can help. My assignment is to create a copy constructor, overloaded assignment operator(=) and a destructor (the 'big three') in C++ to manage an array on the heap. What I wrote below in VS13 produces the correct output but I get a debug error: HEAP CORRUPTION DETECTED:c++ crt detected that the application wrote to memory after end of heap buffer
Can anyone give me some guidance on this, I don't even know where to look. Thanks!!
//copy constructor
myList::myList(const myList& source){
cout << "Invoking copy constructor." << endl;
array_capacity = source.array_capacity; //shallow copy
elements = source.elements; //shallow copy
delete[] arrayPointer;
arrayPointer = new double(source.array_capacity); //deep copy
for (int i = 0; i < array_capacity; i++) //copy array contents
{
arrayPointer[i] = source.arrayPointer[i];
}
}
//overloaded assignment operator
myList& myList::operator=(const myList& source){
cout << "Invoking overloaded assignment." << endl;
if (this != &source){
array_capacity = source.array_capacity; //shallow copy
elements = source.elements; //shallow copy
delete[] arrayPointer; //delete original array from heap
arrayPointer = new double(array_capacity); //deep copy
for (int i = 0; i < source.array_capacity; i++) {//copy array contents
arrayPointer[i] = source.arrayPointer[i];
}
}
return *this;
}
//destructor
myList::~myList(){
cout << "Destructor invoked."<< endl;
delete[] arrayPointer; // When done, free memory pointed to by myPointer.
arrayPointer = NULL; // Clear myPointer to prevent using invalid memory reference.
}
There are a couple of problems with your code. First you are invoking delete on arrayPointer but it hasn't been initialized to anything. This could in fact end up deleting memory you have already allocated or result in an excecption or asset in the implementation of delete. Second when you do initialize it you are allocating a single double initialized to the value of source.array_capacity. Notice the parenthesis used in the line below.
arrayPointer = new double(source.array_capacity);
This will certainly result in undefined behavior during the copy as you end up accessing elements outside the bounds of the array. The above line is present in both your copy constructor and copy-assignment operator and should be using square brackets instead like so:
arrayPointer = new double[source.array_capacity];
You also never check to see if there are any elements stored in the source instance of myList. In this case you should likely be assigning nullptr (or NULL in C++03) to arrayPointer.
As a side note you do not really need to assign NULL to arrayPointer in your destructor. Once the object is destroyed it's gone and any attempt to access it after the fact will result in undefined behavior anyway.
Captain Obvlious pointed out the problem in your copy-constructor already.
You will have noticed that the copy-constructor and the assignment-operator contain a lot of the same code but with a subtle difference. In fact this is probably how you ended up with the error (the assignment operator needs to delete[] the old value, but the copy-constructor doesn't.
Code duplication is bad because it leads to subtle errors like this creeping in. A good pattern you can use here is what's called the copy and swap idiom.
The gist is that you define the copy-constructor, and you also define swap. Then you get assignment for free. This works because swap is easier to implement correctly than the assignment operator, and another major benefit is that nothing can go wrong (you don't have to worry about out-of-memory errors and so on).
In your code; keeping your fixed copy-constructor, you could add inside the class definition:
friend void swap( myList &a, myList &b )
{
std::swap( a.array_capacity, b.array_capacity );
std::swap( a.arrayPointer, b.arrayPointer );
std::swap( a.elements, b.elements );
}
and now the assignment operator is very simple:
myList& myList::operator=(const myList &source)
{
myList temp(source);
swap(*this, temp);
return *this;
}
The old resources from the current object are deleted by the destructor of temp. This version doesn't even need to check for self-assignment because std::swap(x, x) is well-defined.
This can even be optimized further by taking source by value instead of by reference, as explained on the linked page.

Class Assignment Operators

I made the following operator overloading test:
#include <iostream>
#include <string>
using namespace std;
class TestClass
{
string ClassName;
public:
TestClass(string Name)
{
ClassName = Name;
cout << ClassName << " constructed." << endl;
}
~TestClass()
{
cout << ClassName << " destructed." << endl;
}
void operator=(TestClass Other)
{
cout << ClassName << " in operator=" << endl;
cout << "The address of the other class is " << &Other << "." << endl;
}
};
int main()
{
TestClass FirstInstance("FirstInstance");
TestClass SecondInstance("SecondInstance");
FirstInstance = SecondInstance;
SecondInstance = FirstInstance;
return 0;
}
The assignment operator behaves as-expected, outputting the address of the other instance.
Now, how would I actually assign something from the other instance? For example, something like this:
void operator=(TestClass Other)
{
ClassName = Other.ClassName;
}
The code you've shown would do it. No one would consider it to be a particularly good implementation, though.
This conforms to what is expected of an assignment operator:
TestClass& operator=(TestClass other)
{
using std::swap;
swap(ClassName, other.ClassName);
// repeat for other member variables;
return *this;
}
BTW, you talk about "other class", but you have only one class, and multiple instances of that class.
The traditional canonical form of the assignment operator looks like this:
TestClass& operator=(const TestClass& Other);
(you don't want to invoke the copy constructor for assignment, too) and it returns a reference to *this.
A naive implementation would assign each data member individually:
TestClass& operator=(const TestClass& Other)
{
ClassName = Other.ClassName;
return *this;
}
(Note that this is exactly what the compiler-generated assignment operator would do, so it's pretty useless to overload it. I take it that this is for exercising, though.)
A better approach would be to employ the Copy-And-Swap idiom. (If you find GMan's answer too overwhelming, try mine, which is less exhaustive. :)) Note that C&S employs the copy constructor and destructor to do assignment and therefore requires the object to be passed per copy, as you had in your question:
TestClass& operator=(TestClass Other)
almost all said, a few notes:
check for self-assignment, i.e. if (&other != this) // assign
look here for an excellent guide on operator overloading
Traditionnaly the assignment operator and the copy constructor are defined passing a const reference, and not with a copy by value mechanism.
class TestClass
{
public:
//...
TestClass& operator=(const TestClass& Other)
{
m_ClassName= Other.m_ClassName;
return *this;
}
private:
std::string m_ClassName;
}
EDIT: I corrected because I had put code that didnt return the TestClass& (c.f. #sbi 's answer)
You are correct about how to copy the contents from the other class. Simple objects can just be assigned using operator=.
However, be wary of cases where TestClass contains pointer members -- if you just assign the pointer using operator=, then both objects will have pointers pointing to the same memory, which may not be what you want. You may instead need to make sure you allocate some new memory and copy the pointed-to data into it so both objects have their own copy of the data. Remember you also need to properly deallocate the memory already pointed to by the assigned-to object before allocating a new block for the copied data.
By the way, you should probably declare your operator= like this:
TestClass & operator=(const TestClass & Other)
{
ClassName = Other.ClassName;
return *this;
}
This is the general convention used when overloading operator=. The return statement allows chaining of assignments (like a = b = c) and passing the parameter by const reference avoids copying Other on its way into the function call.