I am trying to create a deep copy of a class by overloading the equals operator - however, it does not seem to be working. Any help appreciated!
This is the class I am trying to copy:
class CMap {
public:
int m_nWidth;
int m_nHeight;
char* m_pData;
void setDimensions(int nWidth, int nHeight);
void operator = (CMap* rhs);
};
this is my overloaded operator:
CMap& operator = (const CMap&rhs)
{
if (this == &rhs)
return *this;
memcpy(this -> m_pData, rhs.m_pData, sizeof(char)*rhs.m_nWidth*rhs.m_nHeight);
return *this;
}
and this is the function call in the main. myMap is an array of CMaps.
CMap tempMap;
tempMap.setDimensions(myMap[0].m_nHeight, myMap[0].m_nWidth);
tempMap.m_pData = myMap[0].m_pData;
First: that's not the equals operator, that's the assignment operator.
Second: The assignment operator should have a const & parameter, not a pointer, and returns a reference to the object, not anything.
Third: Except you do something which interferes with the semantics of copying, a assigment overload which does the copy is provided by the compiler automatically.
Respect the point three, you have done one thing which does not do "true" copying: Using a dynamic array through a pointer. The compiler will only copy the pointer, so you have to write your own operator= to copy the array by hand (What you are trying in the question).
The easiest solution is: Use a container like std::vector instead of manual memory management. It has implemented correctly copying and assigment, so yo do not have to write your own operator= in your class.
Related
Constructor for object
Set<T>::Set() {
buckets = new forward_list<T>[9];
numBuck = 9;
numElem = 0;
maxLoad = 9;
}
Overloading of plus operator
Set<T>::operator+(T elem){
Set<T> res;
return res;
}
I don't quite know where to begin with this. This overloaded operator add its parameter elem to a copy of *this and return the result.
ex:
Set<char>setA;
Set<char>setB;
setA.Add('a')
setA.Add('b')
setA.Add('c')
// setA contains {'a','b','c'}
setB = setA + 'd'
// setB should now contain {'a','b','c','d'}
Any guidance?
edit: Clarified operator overload functionality
You can just make a copy function in the set, and use the Add function inside the overload. Demo code:
Set<T>::operator+(T elem)
{
Set<T> result;
result.Copy(*this);
result.Add(elem);
return result;
}
NOTE: Or you can follow #jxh's answer and use the default copy constructor. I would make a Copy function just to be explicit. :)
For the copy of *this, you can modify the definition of res to use the copy constructor.
Set<T> res(*this);
Adding the elem argument uses the same method you used for adding elements to setA.
res.Add(elem);
Since it looks like your code is managing a pointer, you will need to define your own destructor, to release the allocated memory.
Set<T>::~Set() {
delete[] buckets;
}
You are also obligated to implement your own copy constructor and assignment operator, due to the Rule of Three. Your copy constructor would need to performs its own allocation, and the elements from the other Set need to be copied over.
Set<T>::Set(const Set<T> &other) {
numBuck = other.numBuck;
numElem = other.numElem;
maxLoad = other.maxLoad;
buckets = new forwardList<T>[numBuck];
// ... add code to copy elements from other.buckets
}
The assignment operator can be implemented using the copy-swap idiom.
Set<T> & Set<T>::operator = (Set<T> other) {
using std::swap;
swap(*this, other);
return *this;
}
To avoid needing to implement your own destructor / copy constructor / assignment operator methods, you can opt to represent your buckets with a vector rather than managing your own pointer.
std::vector<forward_list<T>> buckets;
I am in a deep confusion and cannot remember the name of the assignment operator of a class, which takes in a different data type than const& of the current class...
so:
struct Thing
{
Thing& operator = (const Thing& other); // This is Assignment Operator
Thing& operator = (int xyz); // What is the name of this?
// really not needed here, just to exemplify that this class has an int
int memberStuff;
};
So, the question: what is the name of Thing& operator = (int xyz); being a member of struct Thing? Is it assignment operator or something else?
Both are assignments.
The only thing is that the first (taking a reference to an object of the same class) could be called a copy assignment operator, while the other is just a plain assignment operator.
In C++ Primer 5th,13.2.1 Class That Act Like Values,the author make a class that act like a value, which means each object have its own copy of the resource that the class manage.The class is below, It is a very simple class, just contain a pointer to a string, and an int, member function are just default constructor and copy-control member.
class HasPtr{
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
HasPtr(const HasPtr &p) :ps(new std::string(*p.ps)), i(p.i){}
HasPtr &operator=(const HasPtr &rhs);
~HasPtr(){ delete ps; }
private:
std::string *ps;
int i;
};
Below is the implement of the operator= given by the book
HasPtr &HasPtr::operator=(const HasPtr &rhs){
auto newp = new std::string(*rhs.ps);
delete ps;
ps = newp;
i = *rhs.i;
return *this;
}
This is good, but i think that we can use the following implement which can avoid delete pointer and allocate new memory.
HasPtr &HasPtr::operator=(const HasPtr &rhs){
*ps = *rhs.ps;
i = rhs.i;
return *this;
}
I test my code works, even self-assignment.However, is there any problem with this code?
No, there is no problem in your code.
*ps
is itself a value type, so you can assign it directly. If you were making changes to improve the code, you might want to go further and change ps into a std::string instead of a std::string*. Then, you could eliminate the need for new and delete from the HasPtr class.
If
*ps
were instead a raw pointer to memory that class HasPtr manages, you would have to write code such as in the example from the book.
In your original example, you had copied the contents of *ps to itself, which is OK. However as the comment to you suggested, this may not always be the case.
As to other solutions, here is one (maybe something like this will be explained later in your book):
#include <algorithm>
//...
HasPtr &HasPtr::operator=(const HasPtr &rhs)
{
HasPtr temp(rhs);
std::swap(ps, temp.ps);
std::swap(i, temp.i);
return *this;
}
This is the copy/swap idiom. A temporary is created from rhs, and the internals of the temporary are swapped out with this's members. The temporary dies, at the end, taking along with it this's former values.
Note that there is no explicit memory allocation, as you're relying on the copy constructor to create the temporary copy initially. This means that this technique requires a working copy constructor, and a working destructor. Once you have those in place, an assignment operator is very simple if done this way, as there is no real "grunt work" coding to do -- the copy constructor would handle it.
So is this easier than the book's version? Depends on how you look at it -- the copy/swap can be used in almost every situation, where you basically only need to start off with working implementations of two of the three functions described in the "rule of 3", namely the copy constructor and destructor. The assignment operator just comes along for the ride by taking advantage of the other two functions, plus perform simple swaps.
I want to redirect my copy operator to my copy constructor. Where in the latter I implement the proper logic for copying/contructing a new class based on the old avaialble class.
However, how is the proper way to do this? I "think" this one is maybe leaking memory, but I don't know how to do it without passing a pointer:
MyClass& MyClass::operator=(const MyClass& a) {
MyClass* b = new MyClass(a);
return *b;
}
Is this OK? If is not, what would be the proper way? Should I change the body of the method or the prototype?
Thank you.
No, an operator= should set the current object attributes to be the same as the object assigned. Your method assigns a new object on the heap, returns it as a reference (essentially leaking it) and leaves the object the operator was called on completely unchanged.
You should implement a method called, for example, CopyFrom(), which assigns all the object's attributes to match those of the passed in object (deep copying any heap allocated pointers whose lifetime is managed by MyClass) and then call THAT from both your copy constructor and your operator=.
class MyClass
{
public:
MyClass( const MyClass& in )
{
CopyFrom( in );
}
MyClass& operator=( const MyClass& in )
{
CopyFrom( in );
return *this;
}
private:
void CopyFrom( const MyClass& in )
{
... copies in's attributes into self.
}
};
As a rule, a copy assignment operator should never create a copy. Rather, it should copy data into the existing object that it's called on (the left-hand side of the assignment). For example:
class MyClass
{
public:
MyClass & operator = (const MyClass & RHS)
{
// Copy data from RHS into 'this'
m_value = RHS.m_value;
return *this;
}
private:
int m_value;
};
In this case, defining your own copy constructor isn't necessary because the default (compiler-provided) one would work fine. It's just an illustration though.
Unfortunately you can't invoke the copy constructor on the existing object. The copy-swap pattern is an alternative, but it can be less efficient.
Unless you're storing pointers inside of MyClass, the correct copy assignment operator is the default-generated one. If, however you need to implement one, you can write it in terms of your copy-constructor via the copy-swap idiom:
MyClass& MyClass::operator = (MyClass const& a) {
MyClass temp(a); // Call the copy constructor
using std::swap;
swap(temp, *this);
return *this;
}
The reason for the using std::swap is to enable argument-dependent lookup. If you define your own swap function for MyClass, it will be called. Else std::swap will be used as a fallback. (EDIT: You do in fact need to implement a custom swap in this case, or else you will get infinite recursion. std::swap will use the assignment operator, which will call std::swap, which will call the...)
The reason that this idiom is well-liked is because std::swap is a no-throw function. If your copy-constructor were to throw an exception, then your object you're assigning to is still in a valid state.
The "proper way" is to implement the assignment operator like an assignment operator: modify the contents of the object on which the operator is being called and return a reference to it.
Your current implementation will result in a memory leak, AND doesn't do any assignment (which is the main point of the assignment operator).
If you only want to write the assignment code once, and your class doesn't allocate memory in the constructor, you could do this:
MyClass::MyClass(const MyClass& a) {
*this = a;
}
MyClass& MyClass::operator=(const MyClass& a) {
if (&a == this)
return *this;
// Do assignment
return *this;
}
But I wouldn't recommend it.
Your code is totally wrong (sorry)! The assignment operator does
not assign anything, but allocates a pointer to a MyClass object,
creating a memory leak. My advice: avoid pointers or use some
smart pointer (shared_ptr, unique_ptr), but that is just a side note.
Maybe this is helpful:
#include <iostream>
#include <limits>
class X
{
public:
X(std::size_t n)
: m_size(n), m_data(new int[n])
{
std::cout << "Construct" << std::endl;
}
~X()
{
std::cout << "Destruct" << std::endl;
delete [] m_data;
}
// Exception safe assignment.
// Note: I am passing by value to enable copy elision and
// move semantics.
X& operator = (X x) {
std::cout << "Assign" << std::endl;
x.swap(*this);
return *this;
}
void swap(X& x) {
std::swap(m_size, x.m_size);
std::swap(m_data, x.m_data);
}
std::size_t size() const { return m_size; }
private:
std::size_t m_size;
int* m_data;
};
int main()
{
X x(1);
try {
x = X(2);
// To provoke an exception:
std::size_t n = std::numeric_limits<std::size_t>::max();
x = X(n);
}
catch(...) {
std::cout << "Exception" << std::endl;
}
std::cout << "Size: " << x.size() << std::endl;
return 0;
}
If you absolutely want to implement the assignment operator by copy constructor, use the following:
MyClass& MyClass::operator=(const MyClass& o)
{
this->~MyClass(); // destroy current object
new(this) MyClass(o); // use the copy constructor
return *this;
}
I cannot think of any situation in which this would be the best thing to do (other answers describe ways of implementation that are better in some situations).
Maybe (just trying to make things up here) if MyClass contains hundreds of int/float fields, and several dynamically-allocated pointers?
Duplicating them in constructor and assignment operator is too tedious and error-prone
Having a copying function that both constructor and assignment operator call - not ideal, because pointers have to be set to NULL first
The code above - will work with no additional effort!
However, having bare (non-smart) pointers in your class is discouraged. If you have such a class, then you have far worse problems than non-working assignment operator - you have to refactor first, and the problem will go away, together with all other bugs.
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;
}