Friday, 20 March 2015

Bitcopy versus initialization in C++

Bitcopy versus initialization in Cpp with examples:

So far, so good. There’s a workable process for passing and returning large simple structures. But notice that all you have is a way to copy the bits from one place to another, which certainly works fine for the primitive way that C looks at variables. But in C++ objects can be much more sophisticated than a patch of bits; they have meaning. This meaning may not respond well to having its bits copied.

Consider a simple example: a class that knows how many objects of its type exist at any one time. We know that we can do this by including a static data member.

This is the sample code that a class that counts its objects:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ofstream out ("Test.out");
class Test
static int isValue;
Test() { isValue++; }
static void GetResult (const string& ocStrMessage = "") {
if(ocStrMessage.size () != 0) out << ocStrMessage << ": ";
out << "isValue = " << isValue << endl;
~Test ()
GetResult ("~Test ()");
int Test::isValue = 0;

/* pass and return by value */
Test MyFun (Test ocTest)
ocTest.GetResult ("ocTest argument inside MyFun ()");
return ocTest;
int main ()
Test ocObj;
Test::GetResult ("after construction of ocObj ");
Test ocObj2 = MyFun (ocObj);
Test::GetResult ("after call to MyFun ()");
getchar ();
return 0;

The class Test contains a static Int isValue and a static member function GetResult( ) to report the value of that isValue, along with an optional message argument. The constructor increments the count each time an object is created, and the
destructor decrements it.

The Test.out file contains the below results:
after construction of ocObj : isValue = 1

ocTest argument inside MyFun (): isValue = 1

~Test (): isValue = 0

after call to MyFun (): isValue = 0

~Test (): isValue = -1

~Test (): isValue = -2

After ocObj is created, the object count is one, which is fine. But after the call to f( ) you would expect to have an object count of two, because ocObj2 is now in scope as well. Instead, the count is zero, which indicates something has gone horribly wrong. This is confirmed by the fact that the two destructors at the end make the object count go negative, something that should never happen. Look at the point inside MyFun( ), which  occurs after the argument is passed by value. This means the original object ocObj exists outside the function frame, and there’s an additional object inside the function frame, which is the copy that has been passed by value. However, the argument has been passed using C’s primitive notion of bitcopying, whereas the C++ Test class requires true initialization to maintain its integrity, so the default bitcopy fails to produce the desired effect.

When the local object goes out of scope at the end of the call to MyFun( ), the destructor is called, which decrements isValue, so outside the function, isValue is zero. The creation of ocObj2 is also performed using a bitcopy, so the constructor isn’t called there either, and when ocObj and ocObj2 go out of scope, their destructors cause the negative values of isValue.

No comments: