Dynamic array... copy constructor, destructor, overloaded assignment operator [closed] - c++

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am studying for my midterm exam. There is going to be a question about setting up an array dynamically, and maybe doing a copy constructor, a destructor and overloading the assignment operator. Can you please verify if I am correct. Also I don't understand what overloading the assignment operator means. Can you help me out with this?
class A
{
int* myArray; //basically I created a pointer called myArray,
A() //are my copy constructors correct? A(), and A(int size)?
{
myArray = 0;
}
A(int size)
{
myArray = new int[size];
}
~A() // I think my destructor is correct
{
delete [] myArray;
}
Can you check my code please? Also how do I overload assignment operator?
Thanks in advance.

The copy constructor is used for creation of object based on another's instance of the same type. You don't have such. You can define it using code like this:
A(const A &other)
{
myArray = new int[other._size];
_size = other._size;
memcpy(myArray, other.myArray, sizeof(int) * _size);
}
You should change your class, so it will store _size of array, you also need to change visibility of your constructors and destructor to public.
The overloaded assignment operator should look like this:
const A &operator=(const A &other)
{
if(this == &other) return *this; // handling of self assignment, thanks for your advice, arul.
delete[] myArray; // freeing previously used memory
myArray = new int[other._size];
_size = other._size;
memcpy(myArray, other.myArray, sizeof(int) * _size);
return *this;
}
You also can add a check of equality of array sizes in this assignment operator, so you will reuse your dynamic array without unnecessary reallocations of memory.

You have correctly defined 2 overloaded constructors and a destructor.
However, you haven't defined an explicit copy constructor properly.
Normally the compiler will generate one for you, and this is called an implicit copy constructor.
The problem with the auto-generated implicit copy constructor in your particular case is that it will only perform a shallow copy of myArray, where it shares the same pointer value but hasn't allocated its own section of memory for myArray.
This means if you delete myArray in the original object, it will affect the copy which is most likely not what you want.
Defining an explicit copy constructor like this will help:
A(const A& copy)
: _size(copy.size), myArray(new int[copy.size])
{
// #include <algorithm> for std::copy
std::copy(copy.data, copy.data + copy.size, data);
}
(Source: Copied from Wikipedia)
If you define the copy constructor like this, you should not need to overload the assignment operator. If you create a new object, and assign it to the first object you created, you will successfully create an independent copy of the first object.
Edit: From this article:
The copy assignment operator differs
from the copy constructor in that it
must clean up the data members of the
assignment's target (and correctly
handle self-assignment) whereas the
copy constructor assigns values to
uninitialized data members.

when dealing with object copy and dynamic memory allocation it's a good idea to use a swap helper function
A(const A& other)
: myArray(0)
, _size(0)
{
if(this != &other) {
A my_tmp_a(other._size);
std::copy(&other[0], &other[other._size], &my_tmp_a[0]);
swap(my_tmp_a);
}
}
const A& operator=(const A& other)
{
if(this == &other) return *this;
A my_tmp_a(other._size);
std::copy(&other[0], &other[other._size], &my_tmp_a[0]);
swap(my_tmp_a);
return *this;
}
void swap(const A& other) {
int* my_tmp_array = this.myArray;
this.myArray = other.myArray;
other.myArray = my_tmp_array;
int my_tmp_size = this._size;
this._size = other._size;
other._size = my_tmp_size;
}

Please make sure define three functions when you want to define one of them. Its called all or none rule
They are:
1) copy constructor.
2) assignment operator.
3) destructor.

Partial answer: overloading a function involves creating different versions of that function which accept different numbers or kinds of arguments. So overloading the assignment operator would involve creating several functions for the assignment operator which allow you to assign objects of various types to a variable of type A.

Related

What happens behind the scenes when manually calling a constructor in C++?

This is an educational question, I am interested in what happens behind the scenes when I do:
SomeClass x(arg1, arg2, arg3); // An instance of SomeClass is constructed.
x = SomeClass(arg4, arg5, arg6); // Intent is to create a new instance.
SomeClass does not have operator= implemented.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens? And when is it a good idea?
This can best be explained with the help of a small example:
Live on Coliru
struct A {
A(int a) { cout << "A::ctor\n"; } //ctor
A(const A& a) { cout << "A::copy\n"; } //copy ctor
A& operator=(const A& a) { cout << "A::operator=\n"; } //copy assign
};
int main()
{
A a(2); //calls constructor
a = A(10); //calls constructor first, then copy assignment
}
Output:
A::ctor
A::ctor
A::operator
The above is pretty self explanatory. For the first, only the constructor gets called. For the second, first the constructor is called and then copy assignment.
SomeClass does not have operator= implemented.
That doesn't matter because the compiler can generate one for you. If you explicitly delete it, then the above code will not compile. However, if you have a move constructor defined then that will be used:
(I highly recommend you read The rule of three/five/zero and understand it. It is among the top 5 things in C++ that you should know.)
A& operator=(const A& a) = delete; //copy assign deleted
A& operator=(A&& other) { cout << "move assigned\n"; } //move assign available
Now you maybe wondering what will happen if both copy and move assign are available. Lets see:
A a(2); //ctor
a = A(10); //ctor + move assign
A b(3); //ctor
b = a; // copy assign only
a = std::move(b); // move assign
For a = A(10) move assign is invoked because A(10) is an rvalue of the same type as what is on the left hand side of the =.
For the last case a = std::move(b);, we explicitly cast b to an rvalue (yes that's what std::move() does). Since it's an rvalue now, move assignment is invoked.
Does the space allocated to x simply get overwritten as if it was newly allocated memory or what exactly happens?
First the temporary is created: A(10). Space will of course be allocated for it.
It's result is then assigned to a, so previous values in a get overwritten
destructor for the temporary will be called
And when is it a good idea?
It is a good idea when you need it, it depends on your usecase. Generally I would recommend that don't copy assign unnecessarily.
Second line is call of constructor followed by call to assignment operator. Assigment default to shallow copy of non-static members into existing storage.
If you defined something that prevented compiler to create default operator=, i.e. you defined move constructor or move assignment, no assignment is possible unless you declared your own (why it is so surprising?) If default shallow copy is fine, you can write following declaration:
SomeClass& operator(const SomeClass&) = default;
= default provides mechanism to declare "default" behavior of special functions.
Now there is move assignment and in such case one would be preferred if it declared in given context. But it won't be declared by compiler if user provided destructor or copy\move constructor\assignment operator.
SomeClass& operator(SomeClass&&) = default;
Difference between two assignments exists only for class-types where "move" semantics may include transfer of ownership. For trivial types and primitive types it's a simple copy.
Compiler allowed to elide some actions including creation of storage for temporary object, so resulting code may actually write new values directly into x storage, provided that such elision won't change program behavior.

call copy constructor from assignment operator function

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.

Why assignment operator is used for deep copy and who calls it

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;
}

Class basic operators

Is it necessary to have a copy constructor, destructor and operator= in a class that have only static data member, no pointer
class myClass{
int dm;
public:
myClass(){
dm = 1;
}
~myClass(){ } // Is this line usefull ?
myClass(const myClass& myObj){ // and that operator?
this->dm = myObj.dm;
}
myClass& operator=(const myClass& myObj){ // and that one?
if(this != &myObj){
this->dm = myObj.dm;
}
return *this;
}
};
I read that the compiler build one for us, so it is better to not have one (when we add a data member we have to update the operators)
If you can't think of anything for the destructor to do, you almost certainly don't need to define it, with the exception of a virtual destructor in a base class. And if you don't need a destructor, you almost certainly don't need to define the copy constructor and assignment operator, and should not do so, as it's easy to get them wrong.
No. The compiler will automatically copy-construct, destruct, and assign all data members automatically. This means that if you have a class where they're all provided, you don't need to write these. I think it's better design to write operators on a per-member basis anyway.
The compiler would provide those itself. By default the copy constructor / assignment operator would copy / assign all members (and base parts of the object if the class is derived), and the destructor does nothing (invokes the destructor of all members / bases, but this is something you can't change even if you provide your own - that happens after the body of the user-defined destructor is exited).
So in this case it is completely unnecessary. All you can achieve is to introduce bugs in the code (e.g you add another member, but forget to update the copy constructor to copy that as well).
myClass& operator=(const myClass& myObj){ // and that one?
if(this != &myObj){
this->dm = myObj.dm;
}
return *this;
}
I don't think you should take "check for self-assignment" dogmatically. Does anything bad happen when you assign an int to itself (even indirectly)?
int a = 10;
int& ref = a;
a = ref;
Avoiding self-assignment is only relevant if the assignment operator first destroys the resources currently held and then creates new ones from the object on the right-hand side. Then it would be a disaster to find out that you have actually indirectly destroyed the right-hand object too.
But even in that case, it would be better to first create the copy of the right-hand side and then destroy the contents of the left-hand side, in which case self-assignment is no problem (except potentially inefficient). For a good way to implement this, Google for copy and swap idiom.

Checklist for writing copy constructor and assignment operator in C++

Please write a list of tasks that a copy constructor and assignment operator need to do in C++ to keep exception safety, avoid memory leaks etc.
First be sure you really need to support copy. Most of the time it is not the case, and thus disabling both is the way to go.
Sometimes, you'll still need to provide duplication on a class from a polymorphic hierarchy, in that case: disable the assignment operator, write a (protected?) copy constructor, and provide a virtual clone() function.
Otherwise, in the case you are writing a value class, you're back into the land of the Orthogonal Canonical Form of Coplien. If you have a member that can't be trivially copied, you'll need to provide a copy-constructor, a destructor, an assignment-operator and a default constructor. This rule can be refined, see for instance: The Law of The Big Two
I'd also recommend to have a look at C++ FAQ regarding assignment operators, and at the copy-and-swap idiom and at GOTW.
The compiler generated versions work in most situations.
You need to think a bit harder about the problem when your object contains a RAW pointer (an argument for not having RAW pointers). So you have a RAW pointer, the second question is do you own the pointer (is it being deleted by you)? If so then you will need to apply the rule of 4.
Owning more than 1 RAW pointer becomes increasingly hard to do correctly (The increase in complexity is not linear either [but that is observational and I have no real stats to back that statement up]). So if you have more than 1 RAW pointer think about wrapping each in its own class (some form of smart pointer).
Rule of 4: If an object is the owner of a RAW pointer then you need to define the following 4 members to make sure you handle the memory management correctly:
Constructor
Copy Constructor
Assignment Operator
Destructor
How you define these will depend on the situations. But things to watch out for:
Default Construction: Set pointer to NULL
Copy Constructor: Use the Copy and Swap ideum to provide to the "Strong Exception Guarantee"
Assignment operator: Check for assignment to self
Destructor: Guard against exceptions propagating out of the destructor.
try to read this.
http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html
is a very good analysis of Assignment operator
I have no idea about exception safely here but I go this way. Let's imagine it's a templated array wrapper. Hope it helps :)
Array(const Array& rhs)
{
mData = NULL;
mSize = rhs.size();
*this = rhs;
}
Array& operator=(const Array& rhs)
{
if(this == &rhs)
{
return *this;
}
int len = rhs.size();
delete[] mData;
mData = new T[len];
for(int i = 0; i < len; ++i)
{
mData[i] = rhs[i];
}
mSize = len;
return *this;
}