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