#include <iostream>
using namespace std;
class samp
{
int *p;
int len;
int idx; // idx denotes the number of elements currently in the array (allocated by p)
public:
samp()
{
len=0;
p=NULL;
idx=0;
cout<<"inside default constructor"<<endl;
}
samp(int len)
{
this->len=len;
p=new int[len];
idx=0;
cout<<"inside parameterized constructor, p="<<p<<endl;
}
samp(const samp &s)
{
len=s.len;
idx=s.idx;
p = new int[len];
for(int i=0;i<idx;i++){
p[i]=s.p[i];
}
cout<<"inside copy constructor, p="<<p<<endl;
}
~samp()
{
cout<<"inside destructor, clearing memory "<<p<<endl;
delete[] p;
p=NULL;
}
void insert(int a)
{
if(idx<len){ // if there is still some place left in the array
p[idx]=a;
idx++;
}
}
void print()
{
for(int i=0;i<idx;i++){
cout<<p[i]<<" ";
}
cout<<endl;
}
};
samp f()
{
samp s(3);
int a;
for(int i=0;i<3;i++){
cin>>a;
s.insert(a);
}
cout<<"now we will return an object from a function"<<endl;
return s;
}
int main()
{
samp s1;
cout<<"now we will try to return an object from a function"<<endl;
s1 = f();
cout<<"function returned"<<endl;
s1.print();
return 0;
}
I am getting the following output and a double free error, because the same memory is being freed twice. Copy constructor is not getting called here because of copy-elision.
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x5573aa164e80
now we will return an object from a function
inside destructor, clearing memory 0x5573aa164e80
function returned
0 0 -1441456112
inside destructor, clearing memory 0x5573aa164e80
As the copy constructor is not getting called, I am getting garbage values as well.
When I use -fno-elide-constructors
as a compiler flag, copy constructor is getting called, but the double memory free error still persists. I am getting an output like this:
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x10c008
now we will return an object from a function
inside copy constructor, p=0x10c040
inside destructor, clearing memory 0x10c008
inside destructor, clearing memory 0x10c040
function returned
85 23 19
inside destructor, clearing memory 0x10c040
Codeblocks is somehow managing to print the values stored in the freed memory, but the same memory is getting freed twice, which I want to avoid.
The destructor is getting called twice here during function return, most probably because it is destructing the local object s of function f once and then destructing the copy object.
If we overload the = operator, the problem of double free disappears.
samp& operator=(const samp &s)
{
len=s.len;
idx=s.idx;
p = new int[len];
for(int i=0;i<idx;i++){
p[i]=s.p[i];
}
cout<<"assigning, new p="<<p<<endl;
return *this;
}
Then I get an output like this:
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x6bc008
now we will return an object from a function
inside copy constructor, p=0x6bc040
inside destructor, clearing memory 0x6bc008
assigning, new p=0x6bc078
inside destructor, clearing memory 0x6bc040
function returned
85 23 19
inside destructor, clearing memory 0x6bc078
My question is, if a copy constructor cannot solve the problem of a memory location getting freed twice, why is it even called during returning an object from a function? Moreover, the code of the = operator overload and copy constructor are almost the same. How is the overloaded = operator solving the problem?
If I return an object from a function, it is highly probable that I will assign it to another object after function call. So do we need to overload the = operator every time we return an object having dynamically allocated memory from a function?
I know about STL vectors. I need to know the behavior of copy constructors in such circumstances.