Answers/Solutions to Exercises in Chapter 10, Exercise 2
E2: Create as simple as possible a C or C++ based program exhibiting the undetermined ownership problem. Then rectify it using smart pointers.
S2: How many times I have seen something like this (continuation from Exercise 1):
.... .... // function DisplayMessage ----------------------------------- void DisplayMessage(int a1,float a2,char* tag) { char *message; message=(char*)malloc(150+strlen(tag)); // create the message ... // do something ... // do something if (tag==0) sprintf(message,"there are %d items with price %f without a tag\n",a1,a2); else sprintf(message,"there are %d items with price %f with tag %s\n",a1,a2,Interpret(tag)); // display the message WriteLog(log,message); free((void*)message); } .... .... // function Interpret ------------------------------------------ char* Interpret(char *tag) { static char buff[80]; if (strcmp(tag,"tag1")==0) strcpy(buff,"Red tag without dot"); else if (strcmp(tag,"tg2")==0) strcpy(buff,"Green tag with dot"); strcat(buff,global_text); return buff; }
Of course, the problems pointed to in Exercise 1 were rectified by deallocation of message in DisplayMessage(). The program works OK until one day the programmer encounters a problem with the global variable global_text that causes an overflow of the buffer buff. An obvious "good" solution to the problem to use dynamic allocation was immediately implemented by the programmer:
// function Interpret ------------------------------------------ char* Interpret(char *tag) { char *buff; buff = (chat*) malloc(strlen(global_text)+50); if (strcmp(tag,"tag1")==0) strcpy(buff,"Red tag without dot"); else if (strcmp(tag,"tg2")==0) strcpy(buff,"Green tag with dot"); strcat(buff,global_text); return buff; }
Of course, buff cannot be deallocated in
Interpret, as it has to be returned to the caller. Of course, the caller has never
bothered to deallocate the interpretation of t tag before
(in fact it must not have been deallocated), so we have a classical example of poor
interproject communication resulting in undetermined ownership problem: who is the owner
of the segment --- the creator Interpret() or the caller
and user DisplayMessage()?
Fixing it with smart pointers:
class SmartCharPtr { public: SmartCharPtr() { ptr=0; owner=0; } ~SmartCharPtr() { if (ptr!=0 && owner) free((void*)ptr); } SmartCharPtr& operator=(SmartCharPtr& p) { // pass along the ownership if (ptr!=0) free((void*)ptr); ptr=p.ptr; owner=1; p.owner=0; return *this; } SmartCharPtr& operator=(char* p) { // obtain the original ownership if (ptr!=0) free((void*)ptr); ptr=p; owner=1; return *this; } operator char* () { return ptr; } protected: char* ptr; int owner; }; // function DisplayMessage ----------------------------------- void DisplayMessage(int a1,float a2,char* tag) { char *message; SmartCharPtr p, q; message=(char*)malloc(150+strlen(tag)); // create the message if (tag!=0) p=Interpret(tag); // ownership passed from Interpret() to p // do something q = p; // ownership passed from p to q // do something if (tag==0) sprintf(message,"there are %d items with price %f without a tag\n",a1,a2); else sprintf(message,"there are %d items with price %f with tag %s\n",a1,a2,(char*)q); // display the message WriteLog(log,message); free((void*)message); } // when DisplayMessage() terminates, both p and q go out of scope, p will be destroyed without // deallocating ptr as it is not owner, q will be destroyed with deallocating ptr, as it is owner// function Interpret ------------------------------------------ SmartCharPtr& Interpret(char *tag) { char *buff; static SmartCharPtr p; buff=(char*)malloc(150+strlen(global_text)); if (strcmp(tag,"tag1")==0) strcpy(buff,"Red tag without dot"); else if (strcmp(tag,"tag2")==0) strcpy(buff,"Green tag with dot"); strcat(buff,global_text); p = buff; return p; }
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 10 Index