0

I have a class for loading and storing (then deleting) image data (pixel and headers). In the constructor I initialize the data and bitmap headers like this:

IMAGE_DATA::IMAGE_DATA():data(0)
{
    memset(&fileheader,0,(sizeof(BITMAPFILEHEADER)));
    memset(&infoheader,0,(sizeof(BITMAPINFOHEADER)));
};

and data is an unsigned char* array allocated with new[...] in load function. The destructor:

IMAGE_DATA::~IMAGE_DATA()
{
    freeData();
};

void IMAGE_DATA::freeData()
{
    delete[] data;

    memset (&fileheader, 0, sizeof(fileheader));
    memset (&infoheader, 0, sizeof(infoheader));
};

Now the problem is that in the filtering class, I pass the class object after loaded the data as a parameter:

IMAGE_DATA image;

image.load("filename"); //load headers and pixel data

FILTER filter;

filter.scale(image,scalefactor,"outputfilename");  //scales the image and write to a .bmp

This is a shortened version of my code. So, the IMAGE_DATA ::load runs smooth, but when the code arrives at the scaling function, I get the following assertion failure:

Debug Assertion Failed!
....
Expression:
_BLOCK_TYPE_IS_VALID(pHeap->nBlockUse)
....

in crt\src\dbgdel.cpp at line 52.

This happens since I made the destructor. For curiosity I changed the paramters so I pass them as reference.

/*FILTER::*/scale(IMAGE_DATA& /*passed as reference*/, unsigned short, const char*); 

And this works now. If I pass 'by value', it seems like the destructor is called, but constructor should also, and there should be no problem since in the constructor I initialize everything.

I want to pass it by value, because I want to left the original unchanged, I just want to use it's data.

How can I make it work without passing as reference and how it is different from passing by value, since by value seems more 'safe'.

EDIT: I've just found a post about this: Side effects when passing objects to function in C++ (I've not searched with the right keywords it seems) So from this post I've read I should make a copy constructor, and an assignment operator.

Community
  • 1
  • 1
David Szalai
  • 2,363
  • 28
  • 47

1 Answers1

1

In C++, there is a 'rule of threes', which basically states, if you have a custom destructor, you also should most probably create a copy constructor and a copy assignment operator.

You are right in assuming that a constructor gets called when you 'pass by value' - however, that is the copy constructor, not the default constructor that you provided.

If you do not define one, the compiler will happily provide one for you - but it will do a 'shallow' copy of all the pointers that you have - essentially, your copy will point to the same memory as the original. I guess you can understand why then it deletes your original :)

divinas
  • 1,787
  • 12
  • 12
  • hm I've just find one post about this:D and I will read about for the rule of three, thanks for the tip +1. I'm gonna accept this in 7 mins – David Szalai Dec 11 '13 at 21:15
  • 1
    And in C++11, "rule of three" has been expanded to "rule of five" - with the introduction of `rvalue references`, there is also a `move constructor` and a `move assignment operator` that you should implement as well. This plays into the notion that you should usually avoid declaring members as raw pointers and use smart wrappers instead and let them deal with copy/move/destroy semantics for you. – Remy Lebeau Dec 11 '13 at 22:34