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).
Related
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.
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.
I try to write a copy constructor for my vector of pointers to object initialized and declared in class Shop. The vector in consideration is:
std::vector <gCustomer*> vCustomer;
It has been also declared in the constructor of gShop and deleted via loop in the destructor.
Now I want to have a deep copy of the vector of pointers in the copy constructor. But nothing gets actually copied, a check of its size remains zero or crashes the program if I manage to run the program and access vCustomer. (Note if I leave the copy constructor out so that the default copy constructor is used, the program runs fine)
gShop::gShop(const gShop & cShop)
{
for(int i = 0; i < (int)vCustomer.size(); ++i)
{
vCustomer[i] = cShop.vCustomer[i];
}
}
Thanks
Note I also have an assigned operator
gShop gShop::operator=(const gShop & rhs)
{
if (this == &rhs) return *this;
for(int i = 0; i < (int)vCustomer.size(); ++i)
{
delete vcustomer[i];
vCustomer[i] = new gCustomer;
vCustomer[i]= rhs.vCustomer[i];
}
}
You've implemented your copy constructor and assignment operator wrongly, they are doing shallow copies not deep copies, and they don't resize the target vector. Here's a deep copy copy constructor
gShop::gShop(const gShop & cShop)
{
for(int i = 0; i < (int)cShop.vCustomer.size(); ++i)
{
if (cShop.vCustomer[i])
vCustomer.push_back(new gCustomer(*cShop.vCustomer[i]));
else
vCustomer.push_back(NULL);
}
}
and here's a deep copy assignment operator
gShop& gShop::operator=(const gShop & rhs)
{
if (this == &rhs) return *this;
// clear any existing data
for(int i = 0; i < (int)vCustomer.size(); ++i)
delete vcustomer[i];
vcustomer.clear();
// add the new data
for(int i = 0; i < (int)rhs.vCustomer.size(); ++i)
{
if (rhs.vCustomer[i])
vCustomer.push_back(new gCustomer(*rhs.vCustomer[i]));
else
vCustomer.push_back(NULL);
}
return *this;
}
Basically the problem was that the you were copying pointers instead of allocating new memory. If you want a deep copy it's essential you allocate new memory.
Of course there is the bigger question, why are you using a vector of pointers at all. One of the big advantage of a vector is that you no longer have to explicitly manage memory, by using a vector of pointers you have lost that benefit. I don't know you program but it seems to me that std::vector<gCustomer> would be better than std::vector<gCustomer*>. With std::vector<gCustomer> you don't need to write a copy constructor or assignment operator, the deep copy will happen automatically (assuming gCustomer does a deep copy).
The loop
gShop::gShop(const gShop & cShop)
{
for(int i = 0; i < (int)vCustomer.size(); ++i)
{
vCustomer[i] = cShop.vCustomer[i];
}
}
uses the wrong limit. It should run from 0 to the length of the existing object:
i < (int)cShop.vCustomer.size()
std::vector<> has copy constructor itself to do the deep copy.
So the copy constructor the compiler gives will do the work you want actually.
If you want to implement it yourself, it's better in the init list of the constructor of gShop.
gShop::gShop(const gShop & cShop):vCustomer(cShop.vCustomer)
{
}
The size of vCustomer is always zero in your copy ctor.
I'm confused with your operator=(). What do you want?
I suggest you read some text books about like c++ primer.
I have a class with a point to dynamically allocated array, so I created copy constructor and assignment operator function. Since copy constructor and assignment operator function do the same work, I call copy constructor from the assignment operator function but get "error C2082: redefinition of formal parameter". I am using Visual Studio 2012.
// default constructor
FeatureValue::FeatureValue()
{
m_value = NULL;
}
// copy constructor
FeatureValue::FeatureValue(const FeatureValue& other)
{
m_size = other.m_size;
delete[] m_value;
m_value = new uint8_t[m_size];
for (int i = 0; i < m_size; i++)
{
m_value[i] = other.m_value[i];
}
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
FeatureValue(other); // error C2082: redefinition of formal parameter
return *this;
}
The offending line isn't what you think it is. It actually declares a variable other of type FeatureValue. This is because constructors to not have names and cannot be called directly.
You can safely invoke the copy assignment operator from the constructor as long as the operator is not declared virtual.
FeatureValue::FeatureValue(const FeatureValue& other)
: m_value(nullptr), m_size(0)
{
*this = other;
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
if(this != &other)
{
// copy data first. Use std::unique_ptr if possible
// avoids destroying our data if an exception occurs
uint8_t* value = new uint8_t[other.m_size];
int size = other.m_size;
for (int i = 0; i < other.m_size; i++)
{
value[i] = other.m_value[i];
}
// Assign values
delete[] m_value;
m_value = value;
m_size = size;
}
return *this;
}
This will works just dandy or you can use the typical guidelines for the copy & swap idiom suggested in Vaughn Cato's answer
You can't directly call a constructor like you would any other method. What you are doing is actually declaring a variable called other of type FeatureValue.
Take a look at the copy-and-swap idiom for a good way to avoid duplication between the assignment operator and the copy constructor: What is the copy-and-swap idiom?
Even better, use a std::vector instead of new and delete. Then you don't need to write your own copy constructor or assignment operator.
Short answer - don't do it.
Details:
// copy constructor
FeatureValue::FeatureValue(const FeatureValue& other)
{
m_size = other.m_size;
delete[] m_value; // m_value NOT INITIALISED - DON'T DELETE HERE!
m_value = new uint8_t[m_size];
for (int i = 0; i < m_size; i++)
{
m_value[i] = other.m_value[i];
}
}
// assignment operator function
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
FeatureValue(other); // error C2082: redefinition of formal parameter
return *this;
}
Notes:
When the copy constructor is called, it's constructing the new object with reference to the object being copied, but the default constructor does not run before the copy constructor. This means m_value has an indeterminate value when the copy constructor starts running - you can assign to it, but to read from it is undefined behaviour, and to delete[] it considerably worse (if anything can be worse than UD! ;-)). So, just leave out that delete[] line.
Next, if operator= tries to leverage the functionality from the copy constructor, it has to first release any existing data m_value is pointing at or it will be leaked. Most people try to do that as follows (which is broken) - I think this is what you were trying for:
FeatureValue& FeatureValue::operator=(const FeatureValue& other)
{
// WARNING - this code's not exception safe...!
~FeatureValue(); // call own destructor
new (this) FeatureValue(other); // reconstruct object
return *this;
}
The problem with this is that if the creation of FeatureValue fails (e.g. because new can't get the memory it wants), then the FeatureValue object is left with an invalid state (e.g. m_value might be pointing off into space). Later when the destructor runs and does a delete[] m_value, you have undefined behaviour (your program will probably crash).
You really should approach this more systematically... either writing it out step by step, or perhaps implementing a guaranteed non-throwing swap() method (easy to do... just std::swap() m_size and m_value, and using it ala:
FeatureValue& FeatureValue::operator=(FeatureValue other)
{
swap(other);
return *this;
}
That's easy and clean, but it has a couple minor performance/efficiency issues:
keeping any existing m_value array around longer than necessary, increasing peak memory usage... you could call clear(). In practice, most non-trivial programs wouldn't care about this unless the data structure in question was holding huge amounts of data (e.g. hundreds of megabytes or gigabytes for a PC app).
not even trying to reuse the existing m_value memory - instead always doing another new for other (that can lead to reduced memory usage but isn't always worthwhile).
Ultimately, the reasons there can be distinct copy constructor and operator= - rather than having the compiler automatically create one from the other - is that optimally efficient implementations can't - in general - leverage each other in the way you'd hoped.
The statement FeatureValue(other); actually invokes the copy constructor to create a new Featurevalue object,which has nothing to do with *this.
During deep copy we are writing overloaded copy constructor and assignment operator.
May i know why we have to write the overloaded assignment operator because we doing the same in overloaded copy constructor(except some check and return this).
Who is calling assignment operator
Follow the Rule of Three:
If you need to write an copy constructor for your class, You also should write the Copy assignment operator and Destructor.
Copy Assignment operator and Copy Constructor both are called Copying functions. They basically help in getting a new copy of an object from an existing object. They both are separate entities invoked in different scenarios. So, just as in case of Copy constructor you ensure that you make deep copies of all pointer members and not just shallow copies, same would applies for copy assignment operator.
An Code Example:
class MyClass obj1, obj2;
class MyClass obj3(obj1); //Calls Copy Constructor
obj1 = obj2; //Calls Copy Assignment Operator
The assignment operator is used if you do this:
MyType my1, my2;
my1 = my2; // same as: my1.operator=(my2);
The copy constructor and the assignment operator usually have very similar code, but if done properly (initializer lists) should be coded differently, used differently, and perform differently.
The copy constructor should use initializer lists. This is used for creating a new vector object that is the same as one already existing.
vector::vector(const vector& b)
:size(b.size),
capacity(b.capacity),
data(new TYPE[size])
{
//there should be minimal code here
//I'm skipping copying the data, because doing it right
//is hard and beside the point
}
vector seven;
seven.push_back(7);
vector seven_copy(seven); //make a new one, same as old
The assignment operator is probably exactly what you have. This is used to reassign an already existing vector object to be the same as one already existing
vector& vector::operator=(const vector& b)
{
//carefully written so self assignment doesn't crash.
TYPE* temp = new TYPE[b.size];
//I'm skipping copying the data, because doing it right
//is hard and beside the point
delete [] data;
//all exceptions that can be thrown, have, so it's safe to modify members now
data = temp;
size = b.size;
capacity = b.capacity;
return *this;
}
vector nine;
nine.push_back(9);
nine = seven; //make an old one the same as another old
It should be noted that the move constructor and move assignment may look vaguely similar, but should probably be different as well.
vector::vector(vector&& b)
:size(b.size)
capacity(b.capacity)
data(b.data) //different!
{
b.data = nullptr;
}
vector& operator=(vector&& b)
{
//since b.data is tied to b.size and b.capacity, it's safest to just swap
//so if someone calls b.push_back() after, it's all still safe.
std::swap(size, b.size);
std::swap(capacity, b.capacity);
std::data(data, b.data);
return *this;
}