CompuServe Thread

C++ question

13 messages in this thread
#29403From: Thomas A. ElamOct 20, 1992 10:55 AM
[Continued] >>I>what does Mr. Stroustrup mean when he talks about turning "unsafe, but generic >>I>list of void* pointers into a … family of type-safe list classes"? (p. 457, >>I>C++ Prog Lang, 2nd ed, Apr 92 corrected printing). >> >>U>He is saying is that you loose typing when you start using a >>U>void * (the void * only possesses the address and the type info is lost >>U>forever as far as the void * itself is concerned). He is also saying that >>U>void * is useful for generic container classes….. >> >>Is this all just to save the extra asterisk (*) that would be necessary in >>a class declaration via the non-intrusive list on pp. 262-267? > >No, has nothing to do what an extra asterisk. void * is just not safe >typing. Consider: > > int *ip; > float *fp; > void *vp; > > ip = fp; // A: what can we say about this? > fp = ip; // B: or this? > > [etc.] I didn't ask my question clearly enough. Please let me try again. I will also try to get Bjarne Stroustrup's BIX address and ask him. There are at least two ways to make a type-safe list class from a list-class template. One is to instantiate a general-purpose template class such as Slist as a list of type-safe pointers. The following is a compilable example: ————————— cut here —————————- struct slink { slink* next; slink() { next=0; } slink(slink* p) { next = p; } }; class slist_base { slink* last; public: void insert(slink*); slist_base() { last = 0; } slist_base(slink* a) { last = a->next = a; } }; void slist_base::insert(slink* a) { if (last) a->next = last->next; else last = a; last->next = a; } [More]
#29490From: Greg Comeau@Comeau CmptgOct 22, 1992 3:41 PM
>There are at least two ways to make a type-safe list class from a >list-class template. One is to instantiate a general-purpose template >class such as Slist as a list of type-safe pointers….. >//… >template<class T> class Tlink : public slink { // … >template<class T> class Slist : private slist_base { // … >main() { Slist<int*> iplist; } What makes this type safe is that Slist get() operations *must* be using the same type as say the Slist insert() (we must allow this assumption). However, since it is non-intrusive, anything can be put on a Slist (even fundamental types) whereas with an Islist, only things derived from slink can be (one may or may not want this binding — I'm sure Stroustrup discusses this even if just in passing… if not I'll say a word or two on it). The idea is that the list is built from the template (hence parameterizing the type) allowing typing because it becomes homogeneous. With the void * _only_ implementation of container classes, *you* must take care of casting all over the place and such. >A second way to make a type-safe list class from a list-class >template is to build a list-of-void* class template from the >above Slist, then instantiate the list-of-void* template >class as a list of type-safe pointers. >template<class T> >class Splist : private Slist<void*> { > void insert(T* p) { Slist<void*>::insert(p); } // …. Now he is "optimizing" for pointers, since pointer are things C and C programmers find useful. The deal is the same as above though: the template allows for non-error-prone control of the types being queried, and on, the list. [More]
#29491From: Greg Comeau@Comeau CmptgOct 22, 1992 3:41 PM
[Continued] So, really then, we don't have two ways to make a class from a template here, but instead a way to have object lists and pointer lists. >It looks to me like Stroustrup is saying > Splist<int> iplist; >is better than > Slist<int*> iplist; >Is it better, and, if so, why? Having just read p255-265 of S2, I don't see him saying either of these two things. He gives the proper explanation and time to each thing. For instance, he spends much time on the non-pointer, and then in the sake of specialization mentions "Since lists of pointers are so useful it is a good idea to name them specifically." This is where you get the Splist from. Re his comment on p457 "Splist turns the unsafe, but generic, list of void * pointers into a much more useful family of type-safe list classes." Notice these "magic" in Splist. void* by itself it not typesafe. That was why I showed that list of different pointer assignment in my last messages. If you pull something out of a void * in C++ you must cast it. +++You are only supposed to pull out of a void * the "same type" that put into it.+++ The language doesn't inforce this though and so it is up to your discpline. Like the code I showed: "void *vp; int *ip; float *fp; vp = ip; fp = (float*)vp;' is most likely an error at runtime even with the cast. The Splist is going to throw typing atop the list because we must feed the type into Splist when we create on of them. At that type should be honor by the member functions. For instance, notice how insert accepts a T and how get returns a T. This allows honoring of +++ and now the compiler will complain if something is not right. Further, since Splist is built upon Slist<void *>, there does not need to be specific Slist <T? *> member function for every type that your program uses. [More]
#29492From: Greg Comeau@Comeau CmptgOct 22, 1992 3:41 PM
[Continued] >>Why is anybody using it? > >Is anybody? Stderr is great on Unix, but it seems to me its >only purpose under AmigaDOS is to make it easier to port Unix >programs to the Amiga. Although stderr of course originated on UNIX as there is where the first C implementation were, attaching it to UNIX strictly nowadays is an erroneous thought nowadays. >If the user could specify an output file, could he then specify a pipe >device? There are a couple or more Amiga pipe devices in the public domain. >Maybe that would solve the appending problem. If it were only that simple! We could add the code to allow the user to specify an output file in a day. That is no problem. The problem is that we fire up C compiler, linkers, etc, and all do not appear to have this capability (it must append, not just output). OTOH, maybe I've been misinformed about AmigaDOS pipe devices all this time. If I can't control every executable run by como.rexx, can this still be done? [More]
#29493From: Greg Comeau@Comeau CmptgOct 22, 1992 3:41 PM
[Continued] >>Have you sent Stroustrup mail on BIX asking him if he has complete code for >>this example? >I will try to find his address and take it up with him. Please do not necessarily say I said for you to demand this from him. As you are saying that the code is alledgedly incomplete as posted in *his* book (and maybe he intended it that way), all I am saying then is that he is a likely source of telling you where (if anywhere) to look in the book or electronically somewhere. >Your message gave me the idea to try to exactly >duplicate Stroustrup's code. I guess I'm confused. I thought you said the S2 code was incomplete? >By doing that, I think I have found a bug >in Cfront. I'm not sure whether it's an AT&T bug or a Comeau Computing >bug (or my bug). By merely declaring two objects of similar but >distinctly named classes (just before function "main"), I get the error: >"aplist.h", line 116: internal <<AT&T USL C++ Language System <3.0> 09/15/91>> e Interesting, we compiled the code under MS-DOS, then UNIX SVR4 (and with 3.0.1 as well as 3.0 here), and then under AmigaDOS, and only the AmigaDOS one produced the result you got (the others compiled fine). It blew up in a routine which allocates more symbol table space for cfront. It does not look like your bug, and 3.0 is known to have some template problems from AT&T (I'll have to work on checking this out with a 3.0.1 under AmigaDOS).
#29515From: Thomas A. ElamOct 22, 1992 10:07 PM
>>>Have you sent Stroustrup mail on BIX asking him if he has complete code for >>>this example? >>I will try to find his address and take it up with him. > >Please do not necessarily say I said for you to demand this from him. >As you are saying that the code is alledgedly incomplete as posted in *his* >book (and maybe he intended it that way), all I am saying then is that he is a >likely source of telling you where (if anywhere) to look in the book or >electronically somewhere. No, I'd never demand. (I think the French "demander" has a different connotation, though. I don't know if you are French, but your name sounds like it is. 😉 I just asked him as if the idea came from me. >>Your message gave me the idea to try to exactly >>duplicate Stroustrup's code. > >I guess I'm confused. I thought you said the S2 code was incomplete? Incomplete in the sense of requiring a lot of reading and page flipping to be sure the pieces are all part of the same puzzle. Also, first I tried to derive the nodes and lists from Amiga nodes and lists to derive some possible benefits from pre-existing Amiga utilities. Then your message gave me the idea to be more careful and go back to try Stroustrup's code exactly as it is. >>By doing that, I think I have found a bug >>in Cfront. I'm not sure whether it's an AT&T bug or a Comeau Computing >>bug (or my bug). By merely declaring two objects of similar but >>distinctly named classes (just before function "main"), I get the error: >>"aplist.h", line 116: internal <<AT&T USL C++ Language System <3.0> 09/15/91>> e > >Interesting, we compiled the code under MS-DOS, then UNIX SVR4 (and with >3.0.1 as well as 3.0 here), and then under AmigaDOS, and only the AmigaDOS one >produced the result you got (the others compiled fine). It blew up in a >routine which allocates more symbol table space for cfront. It does not >look like your bug, and 3.0 is known to have some template problems from >AT&T (I'll have to work on checking this out with a 3.0.1 under AmigaDOS). Now we're cookin'! Great! Please keep me posted. I'm not sure what I want to do without templates. I need them right away. Thanks for looking into this.
#29669From: Greg Comeau@Comeau CmptgOct 26, 1992 10:42 PM
Glad we're finally in sync on some of these issues. I wasn't always clear what you were asking, so I guess you weren't always clear what I was responding to 😉
#29516From: Thomas A. ElamOct 22, 1992 10:25 PM
>>If the user could specify an output file, could he then specify a pipe >>device? There are a couple or more Amiga pipe devices in the public domain. >>Maybe that would solve the appending problem. > >If it were only that simple! We could add the code to allow the user to >specify an output file in a day. That is no problem. The problem is that >we fire up C compiler, linkers, etc, and all do not appear to have this >capability (it must append, not just output). OTOH, maybe I've been >misinformed about AmigaDOS pipe devices all this time. If I can't control >every executable run by como.rexx, can this still be done? > I don't understand why you can't control every executable run by como.rexx. Maybe ARexx won't give you the control you need. I don't know. What kind of control do you mean? It seems to me that you would want a child process (the C compiler, linker, etc.) to inherit its standard I/O from its parent shell so that when it dies the next child can inherit the same standard I/O from the parent and just write to it (standard output or standard error). Are you fam- iliar with Mr. Fred Fish's freely redistributable Amiga disk library? I can usually find what I need pretty fast there, though new disks are added to the library so fast (about 100 to 150 per year, I think) that it's not always easy to find an up-to-date cataloging of it. I cannot overpraise this library. It is an ad hoc central clearinghouse for probably nearly all the worthwhile public domain, shareware, freeware, demoware, etc. software ever written for the Amiga. (And there certainly is an incredible amount of it.) Just about anything any programmer ever dreamed of doing with the Amiga has been done in one of these programs. Many include source code. Here are a couple of samples of software packages in the library (these are just examples, I'm not sure at all a pipe would work; after all, somehow you'd have to keep it open somehow, and then how could it be closed?): PipeDevice "A working 'pipe:' device, which allows the standard output of one process to be fed to the standard input of another process, with both processes running concurrently. Author: Matt Dillon" Disk #55. [More]
#29670From: Greg Comeau@Comeau CmptgOct 26, 1992 10:43 PM
> >we fire up C compiler, linkers, etc, and all do not appear to have this > >capability (it must append, not just output). OTOH, maybe I've been > >misinformed about AmigaDOS pipe devices all this time. If I can't control > >every executable run by como.rexx, can this still be done? >I don't understand why you can't control every executable run by >como.rexx. Maybe ARexx won't give you the control you need. I >don't know. Does anybody out there know 100% for sure? >you would want a child process (the C compiler, linker, etc.) to >inherit its standard I/O from its parent shell so that when it dies >the next child can inherit the same standard I/O from the parent and >just write to it (standard output or standard error). That definitely cannot be done with Arexx. At least not directly. That was the basis of our original attempt at doing this. Upon closing and reopening stdin and stderr in arexx, nothing seemed to have changed and folks on BIX confirmed that as stderr is not quite what one expects under AmigaDOS, that was that. If it isn't, I'd love to know.
#29517From: Thomas A. ElamOct 22, 1992 10:34 PM
[Continued] PipeHandler "An AmigaDOS pipe device which supports OPEN, CLOSE, READ, WRITE, LOCK, EXAMINE, and EXNEXT. [My note: these are AmigaDOS standard messages to file system devices, I believe.] Thus you can have "named pipes". It also supports "taps" on a pipe, to capture all data flowing through the pipe. Author: Ed Puckett" Disk #84. APipe "An 'Amiga pipe' device…. Author: Per Bojson" Disk #601 FifoLib "FIFO: is like PIPE: but is based on fifo.library rather than its own implementation. Fifo.library is a general fifo library implementation that supports named fifos, writing to a fifo from a hardware exception, multiple readers on a fifo with each getting the same data stream, efficient reading, and an automatic or manual flow control. Programs that require non-blocking IO can access one side of a FIFO: connection via the fifo.library [my note: Amiga shared run- time library] instead of the FIFO: device…. Author: Matt Dillon" Disk #588 SKsh "A ksh-like shell for the Amiga. Some of its features include … [my note: many ksh features], I/O redirection, pipes, …. Author: Steve Koren" IPDevice "… A pipe-like DOS device that passes data immediately rather than waiting until a buffer is full. It also allows multiple writers to a single channel, maintained connections, and piped connections to a Shell. Author: Pete Goodeve" Disk #374 I'd also check out Matt Dillon's latest UUCP (on a Fish disk), ARP (basically extends an earlier version of AmigaDOS, but still somewhat popular, I think), because several facilities tag along with these packages, and talk to some Amiga gurus. A lot of them would probably be extremely happy to offer some help. I can't believe this problem cannot be overcome without rewriting the Amiga system software. I'm not currently competant to give specific help on this subject (although I think I've delved into Unix I/O, processes, pipes, etc. pretty deeply). I wish you could explain exactly what you are trying to do so I could understand it. If it would help, we could use Bach's book on the Unix kernel as a reference point (especially to clarify our language). If you could show me your relevant code, it would help. I'd be willing to look into this problem a bit, as my time allows. I'd like to see it worked out.
#29671From: Greg Comeau@Comeau CmptgOct 26, 1992 10:43 PM
>If you could show me your relevant code, it would help. I'd be willing >to look into this problem a bit, as my time allows. I'd like to see it >worked out. It's been quite some time since we looked at this problem but as I recall it, it was as simple as this. Given 'blah.c': #include <stdio.h> main() { fprintf(stderr, "abc\n"); } compiled to 'blah', and given say 'rb.rexx': blah blah then 'rb.rexx' needs to capture the two "abc\n" somehow.
#29514From: Thomas A. ElamOct 22, 1992 10:04 PM
>>It looks to me like Stroustrup is saying >> Splist<int> iplist; >>is better than >> Slist<int*> iplist; >>Is it better, and, if so, why? > >Having just read p255-265 of S2, I don't see him saying either of these two >things. He gives the proper explanation and time to each thing. For >… I'm not sure if we understand each other on this topic, but as I replied to your last message, I finally got the understanding I sought, and thank you for your help getting me there. I had trouble saying exactly the right question. Here it is again, stated a little differently, and in 3 parts: [Part 1] Why does Stroustrup comment on p. 264, "Since lists of pointers are so useful it is a good idea to name them specifically …"? [Part 2] Then is Splist<int> iplist; sometimes better than Slist<int*> iplist; ? Particularly, can it be *significantly* better. [Part 3] If so, when and why? The answers I have gleaned are: [Part 1] Compared to lists of pointers inheriting directly from general lists, lists of pointers inheriting directly from lists of void pointers share more of their implementation. [Part 2] When the sharing of more implementation saves significant code space, the answer is "yes". [Part 3] See [Part 2]. Saving code space is sometimes, in some circumstances, worthwhile.
#29513From: Thomas A. ElamOct 22, 1992 10:02 PM
>>There are at least two ways to make a type-safe list class from a >>list-class template. One is to instantiate a general-purpose template >>class such as Slist as a list of type-safe pointers….. >>//… >>template<class T> class Tlink : public slink { // … >>template<class T> class Slist : private slist_base { // … >>main() { Slist<int*> iplist; } > >What makes this type safe is that Slist get() operations *must* be using the >… > >>A second way to make a type-safe list class from a list-class >>template is to build a list-of-void* class template from the >>above Slist, then instantiate the list-of-void* template >>class as a list of type-safe pointers. >>template<class T> >>class Splist : private Slist<void*> { >> void insert(T* p) { Slist<void*>::insert(p); } // …. > >Now he is "optimizing" for pointers, since pointer are things C and C >… I finally understood when Mr. Stroustrup (in message 2995 in the c.plus.plus/beginner forum on BIX) stated that "… there is no (significant) difference …. However, in a a typical program we will use lists of many kinds of pointers…. Unfortunately, this would imply generating [many] variants of the Slist code … On the other hand if we used … Splist<…> … the [many] types [of Slist] would all share the Slist<void*> implementation…. … for many (most?) real projects the saving in space is significant." Sorry, you probably said it too, but I just didn't get it. Anyway, the intellectual satisfaction for me of under- standing this is intense, and you helped get me on the right track. Thank you very much.