Answers/Solutions to Exercises in Chapter 10, Exercise 7
E7: Write a simple C++ using smart pointers that use
non-intrusive reference counting. Have them write into a log
(you can use the logging functions from Appendix D).
S7: A sample program is below --- based on the class SmartCharPtr from previous exercises. Red indicates the modifications (additions) to SmartCharPtr class to accommodate this tracing.
#include <string.h> #include <stdio.h> #include <stdarg.h> #include <stdlib.h> void sys_exit(char *fmt, ...); void sys(char *fmt, ...); void msg_exit(char *fmt, ...); void msg(char *fmt, ...); void Sys_exit(char *fmt, ...); void Msg_exit(char *fmt, ...); void Sys(char *fmt, ...); void Msg(char *fmt, ...); void print_msg(char *fmt,va_list ap,char* where); void open_log(char* name); char logpath[500] = ""; char buf[500]; // this class is a link in a double-linked list of references by X template<class X> class REFLINK { public: REFLINK() { address=0; nextRef=prevRef=0; } REFLINK(void* ad) { address=ad; nextRef=prevRef=0; } void ResetFirst(X* x) { first=x; } void NewFirst(void* ad,X* x) { if (ad==address) { first=x; return; }else{ if (nextRef==0) { nextRef = new REFLINK<X>; nextRef->address=ad; nextRef->nextRef=0; nextRef->prevRef=nextRef; nextRef->first=x; return; }else{ nextRef->NewFirst(ad,x); return; } } } X* Add(void* ad,X* x) { // Add x as the first, return the former first if (ad==address) { X* p; p=first; first=x; return p; }else{ if (nextRef==0) { nextRef=new REFLINK<X>; nextRef->address=ad; nextRef->nextRef=0; nextRef->prevRef=nextRef; nextRef->first=x; return x; }else{ return Add(ad,x); } } } REFLINK* RemoveRef(void* ad,REFLINK* st) { REFLINK* p; if (ad==address) { if (prevRef==0) { // first reference if (nextRef==0) { // last reference delete this; return 0; // no list, new empty start }else{ // not the last one nextRef->prevRef=0; p = nextRef; delete this; return p; // new start } }else{ // not the first one if (nextRef==0) { // last one prevRef->nextRef=0; p = prevRef; delete this; return st; // keep original start }else{ // not the last one prevRef->nextRef=nextRef; nextRef->prevRef=prevRef; delete this; return st; // keep original star } } }else{ return nextRef->RemoveRef(ad,st); } } protected: void* address; // this will be the root of ref siblink list for this address REFLINK* nextRef; // previous ref REFLINK* prevRef; // next ref X* first; // first in the ref list }; // this is "added" to the class X for reporting what th object of class X reference // it is a link in "ref siblink list" --- it ties together the X objects that reference // the same address template<class X> class LINK { public: LINK() { prev=next=0; } void SetPrev(X* t) { prev=t; } protected: X* prev; X* next; static REFLINK<X>** start; void Remove(void* p) { // remove yourself from ref siblink list if (prev==0 && next==0) { // you are the only one of ref siblink list *start=(*start)->RemoveRef(p,*start); }else if (prev==0) { (*start)->NewFirst(p,next);// you are the first in ref siblink list next->prev=0; next=0; return; }else{ // you are in the middle of ref siblink list if (prev) prev->next=next; if (next) next->prev=prev; prev=next=0; } } void Add(void* p,X* x) { // add yourself to the list of ref siblinks as first if (*start==0) { *start = new REFLINK<X>(p); (*start)->ResetFirst(x); prev=0; }else{ prev=0; next=(*start)->Add(p,x); next->prev=x; } } void Report1(X* t) { X* p; int i; Msg("SmartCharPtr(%x) references address %x\n",t,(char*)t); for(i=1,p=prev; p!=0; p=p->prev,i++) Msg("SmartCharPtr(%x) references address %x\n",p,(char*)p); for(p=next; p!=0; p=p->next,i++) Msg("SmartCharPtr(%x) references address %x\n",p,(char*)p); Msg("%d SmartCharPtr's reference address %x\n",i,(char*)t); } }; class SmartCharPtr : private LINK<SmartCharPtr> { public: SmartCharPtr() { ptr=0; owner=0; } SmartCharPtr(char* p) { ptr=p; owner=1; Add((void*)ptr,this); } SmartCharPtr(SmartCharPtr& p) { ptr=p.ptr; owner=1; p.owner=0; Add((void*)ptr,this); } SmartCharPtr& operator=(SmartCharPtr& p) { if (ptr!=0) { Remove((void*)ptr); if (owner) delete[] ptr; } ptr=p.ptr; Add((void*)ptr,this); p.owner=0; return *this; } ~SmartCharPtr() { if (ptr!=0) { Remove((void*)ptr); if (owner) delete[] ptr; } } SmartCharPtr& operator=(char* p) { if (ptr!=0) { Remove((void*)ptr); if (owner) delete[] ptr; } ptr = new char[strlen(p)+1]; strcpy(ptr,p); owner=1; Add((void*)ptr,this); return *this; } void Report() { Report1(this); } operator char* () { return ptr; } protected: char *ptr; int owner; }; REFLINK<SmartCharPtr>* start1=0; REFLINK<SmartCharPtr>** LINK<SmartCharPtr>::start=&start1; SmartCharPtr* doit() { char* p = new char[30]; strcpy(p,"string1"); SmartCharPtr p1(p); SmartCharPtr p2; p2 = p1; p1.Report(); Msg("-----------------------\n"); SmartCharPtr* p3; p1.Report(); Msg("-----------------------\n"); p3 = new SmartCharPtr(p2); p1.Report(); Msg("-----------------------\n"); return p3; } int main() { open_log("mylog"); SmartCharPtr* p; p = doit(); p->Report(); delete p; //now the value of start1 should be 0, as all references are deleted, so let us see Msg("start1=%d\n",start1); return 0; } /* simplified logging functions --- without locking, without time, without multiprocessing, without multithreading */ /* function sys_exit ------------------------------------------- */ void sys_exit(char *fmt, ...) { va_list ap; printf("[system error] "); va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); exit(1); }/* end sys_exit */ /* function sys ------------------------------------------- */ void sys(char *fmt, ...) { va_list ap; printf("[system error] "); va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); }/* end sys */ /* function msg_exit ------------------------------------------- */ void msg_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); exit(1); }/* end msg_exit */ /* function msg ------------------------------------------- */ void msg(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); }/* end msg */ /* function Sys_exit ------------------------------------------- */ void Sys_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[system error] "); va_end(ap); exit(1); }/* end Sys_exit */ /* function Msg_exit ------------------------------------------- */ void Msg_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); exit(1); }/* end Msg_exit */ /* function Sys ------------------------------------------- */ void Sys(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); }/* end Sys */ /* function Msg ------------------------------------------- */ void Msg(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); }/* end Msg */ /* function print_msg ------------------------------------------- */ void print_msg(char *fmt,va_list ap,char* where) { FILE* fp; vsprintf(buf,fmt,ap); if (where==0) printf("%s\n",buf); else{ fp = fopen(logpath,"a"); if (fp == NULL) { printf("problem to open log\n"); exit(1); } fprintf(fp,"%s%s\n",where,buf); } }/* end print_msg */ /* function open_log ------------------------------------------ */ void open_log(char* name) { FILE* fp; strcpy(logpath,name); fp = fopen(logpath,"w"); if (fp == NULL) { printf("error opening log\n"); exit(1); } fprintf(fp,"log opened\n"); fclose(fp); }/* end open_log */
(Annotated) Log:
log opened (p1 set to string, p2 set to p1) []SmartCharPtr(12fefc) references address 12fefc []SmartCharPtr(12feec) references address 12feec []2 SmartCharPtr's reference address 12fefc []----------------------- (p3 defined) []SmartCharPtr(12fefc) references address 12fefc []SmartCharPtr(12feec) references address 12feec []2 SmartCharPtr's reference address 12fefc []----------------------- []SmartCharPtr(12fefc) references address 12fefc (p3 set to p2) []SmartCharPtr(12feec) references address 12feec []SmartCharPtr(431fe0) references address 431fe0 []3 SmartCharPtr's reference address 12fefc []----------------------- (p1,p2 go out of scope) []SmartCharPtr(431fe0) references address 431fe0 (p3 as returned by doit()) []1 SmartCharPtr's reference address 431fe0 []start1=0 (after delete)
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 10 Index