Path: utzoo!attcan!uunet!samsung!zaphod.mps.ohio-state.edu!mips!prls!pyramid!infmx!briand From: briand@infmx.UUCP (brian donat) Newsgroups: comp.lang.c++ Subject: Re: Beginner's Corner Summary: Feed Back 2 of 4 Keywords: First C++ Code. Message-ID: <4337@infmx.UUCP> Date: 26 May 90 00:19:24 GMT References: <4316@infmx.UUCP> Organization: Informix Software Inc., Menlo Park, CA. Lines: 171 // // 2 of 4 // // Ready for bite number 2? It deals with splitting up things // over files. // // Believe me! This was fun to do the first time through. There // was a point in time, when I really didn't think I knew at // all what I was doing. // // First off, it appears that enum types can not be multiply // declared in more than one header file that will later be // #included in one source or linked object. You can't // extern the blasted things either! // So, don't get sucked into thinking that they'll do you a // good turn if you use them in a class! // After about an hour of fiddling around with enum types inside // a class, I concluded emphatically that they should be // totally banned from inclusion within class scope. // // Dr. Cline from Clarkston U. in NY emphasized this hazard // and also demonstrated that code can be written more compactly // without using 'boolean' as an enumeration type. // // Notice however, how I've used #define below. // // Dr. Cline also pointed out how my constructor could be compacted // and be made more readable by using the initialization list // feature. // // Discussion continued below. ---------------------------------Cut HERE--------------------------------- /////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ // \\ // vlist.c Version 2.00 \\ // VLIST class member functions: May 25, 1990, Brian L. Donat \\ // \\ /////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ #include #include "vlist.h" #define FALSE 0 #define TRUE 1 int listError = FALSE; VLIST::VLIST() : listsize(0), head(new NODE), tail(new NODE), cnode(head) { if(!head || !tail) abort(); // No Memory?! head->previous = tail->next = 0; head->next = tail; tail->previous = head; } VLIST::~VLIST() { headend(); while(listsize) remove(); delete head; delete tail; } void VLIST::headend() { cnode = listsize ? head->next : head; } void VLIST::tailend() { cnode = listsize ? tail->previous : tail; } int VLIST::find(ELEMENT E) { for(NODE *nptr = head; nptr->next && nptr->data != E; nptr = nptr->next); cnode = (nptr->next) ? nptr : cnode; return nptr->next != 0; } void VLIST::insert(ELEMENT E) { NODE *pptr = cnode->previous; // If at the head of an empty list, fake an add(). if(!listsize && !cnode->previous) { cnode = tail; pptr = head; } // build new NODE NODE *newptr = new NODE; newptr->data = E; newptr->next = cnode; newptr->previous = cnode->previous; // Update Adjacent Nodes pptr->next = newptr; cnode->previous = newptr; cnode = newptr; listsize++; } void VLIST::remove(void) { listError = FALSE; if(!listsize) listError = TRUE; else if(!cnode->previous) listError = TRUE; else if(!cnode->next) listError = TRUE; else { NODE *pptr = cnode->previous; NODE *nptr = cnode->next; // let the previous and next NODEs reference each other. pptr->next = cnode->next; nptr->previous = cnode->previous; // remove the current node. delete cnode; // If the next pointer is not tail, make it current, // else make the previous pointer the current NODE. cnode = (nptr->next) ? nptr : pptr; listsize--; } } void VLIST::step() { cnode = cnode->next ? cnode->next : cnode; cnode = cnode->next ? cnode : cnode->previous; } void VLIST::backstep() { cnode = (cnode->previous) ? cnode->previous : cnode; cnode = (cnode->previous) ? cnode : cnode->next; } ELEMENT VLIST::getval(void) const { listError = FALSE; if(!cnode->previous || !cnode->next) listError = TRUE; return cnode->data; } ---------------------------------Cut HERE--------------------------------- // One of the only other odd things I noticed here is the following // return nptr->next != 0; // The above tidbit of code is a rather sneaky way of insuring an // integer return type. // True! nptr->next could be 0 or some lvalue. // If it had been written return nptr->next however, the compiler // bellyaches about an incompatible return type and a (int) cast // would have to be used. // Note too, that in the find() member that awful boolean enum type // is blasted to kingdom come! // // One thing that raises questions in my mind at this point is // error reporting. I originally defined some of these class // members with built in error messages, but Yeccchhh! Of course, // I didn't want to leave 'em in there. // // However, as an alternative, I stuck up a global 'listError' to // communicate the error outside the class. // Now it occurs to me that I could have used a static listError // private to the class and provided members to get at it, but // Yechhhh!!! // Notice too, how I'm having to initialize listError at the top // of every member that needs to use it. // I suppose the best thing might be to have an internal escape, // perhaps with setjmp() and longjmp() stuck in there, operating // on either a static listError or still, the global. // Anybody got a good idea on how to monitor member errors safely, // without having to abort() or exit(), or without having to // play with added overhead, etc... // -- infmx!briand@pyramid