I am trying to learn C++ and was writing programs to learn Copy Constructors and Operator overloading. I am surprised that the below program when Copy constructor is used do
The behavior of "Undefined behavior" is just undefined. That means, no one put effort into that cases because that cases should not happen. Even a working program can be "Undefined behavior".
In your special case of an double delete, what happens, really depends on the implementation of the allocator. A usual implementation is to put released memory into a list and a next allocation will be satisfied with an element out of this list. If you double delete a chunk of memory, it will be added to the list twice. And then two allocation will be satisfied with the very same chunk of memory and thus two object will be created at the same memory location.
BTW: You destructor is already broken, as it doesn't use the array delete.
I wirte this piece of test code, hope it will help here, I think crush is related to platform a lot, it is not just by chance, since this piece of code crush in linux ,but works fine in codeblock IDE
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
class XHandler
{
public:
XHandler()
{
data = new char[8];
strcpy(data, "NoName");
std::cout<< "default construcor is called" << std::endl;
}
XHandler (const char *str)
{
data = new char [strlen(str) + 1 ];
strcpy (data, str);
std::cout<< "param construcor is called" << std::endl;
}
XHandler (const XHandler &xh)
{
data = xh.data;
std::cout<< "copy construcor is called" << std::endl;
}
XHandler& operator = (const XHandler &xh)
{
data = xh.data;
std::cout<< "operator construcor is called" << std::endl;
return *this;
}
~XHandler()
{
std::cout<< "destrucor is called" << std::endl;
print_dir();
if (data)
{
delete [] data;
data = NULL;
std::cout<< "delete data" << std::endl;
}
}
void debug()
{
cout << data <<endl;
}
void print_dir()
{
printf("location: %p\n",data);
}
private:
char *data;
};
int main()
{
XHandler wm("hello"), wb("there");
wm.debug();
wb.debug();
wm.print_dir();
wb.print_dir();
XHandler wc (wm);
wc.print_dir();
wc.debug();
XHandler wd;
wd = wc;
wd.debug();
}
it crush in linux gcc4.1.2 ,it outputs
param construcor is called
param construcor is called
hello
there
location: 0x502010
location: 0x502030
copy construcor is called
location: 0x502010
hello
default construcor is called
operator construcor is called
hello
destrucor is called
location: 0x502010
delete data
destrucor is called
location: 0x502010
*** glibc detected *** ./test: double free or corruption (fasttop): 0x0000000000502010 ***
Your program has undefined behavior.
Problems:
data = new char (strlen(str) + 1 );
This doesn't allocate strlen(str) + 1
characters. Instead, it allocates a single character and places the strlen(str) + 1
value within. When you perform a strcpy afterwards, you are corrupting the stack through buffer overflow (writing strlen(str) -1 chars past the allocated space). To allocate an array you should use square brackets:
data = new char [strlen(str) + 1 ];
Second, you should delete the data with delete[] data;
. Otherwise, you get undefined behavior.
Third, your strcpy code doesn't copy the NULL terminator of the string. You should add a null terminator:
data[ strlen(str) ] = 0;
after the strcpy lines; (see comments).
Additionally, there is no requirement that an application would crash on double delete. Deleting the same memory twice is UB.