Newsgroups: comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!rochester!udel!news.mathworks.com!news.ultranet.com!news.sprintlink.net!howland.reston.ans.net!ix.netcom.com!netcomsv!uu3news.netcom.com!netcomsv!uucp3.netcom.com!medicus!billf
From: billf@medicus.com (Bill Foote)
Subject: Re: Has C++ had its day?
Message-ID: <1995Jun16.175012.21514@medicus.com>
Organization: Medicus Systems Corp.
References: <3rmtdp$5b1@cody.atnet.co.at>
Date: Fri, 16 Jun 1995 17:50:12 GMT
Lines: 140

In article <3rmtdp$5b1@cody.atnet.co.at> bernhard@cody.atnet.co.at (Bernhard Strassl) writes:
>> In article <3qo3i9$8oi@manitou.cse.dnd.ca>,
>> Kirk Pepperdine <kpepperd@cse.dnd.ca> wrote:
>> > [........]
>> >problem which made project managers afraid of C, hidious memory leakage
>> >errors that you can't find.
>
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
>When using appropriate programming tools (like PURIFY) you
>can forget about memory errors.

That's a bit of an exaggeration.  For example, here's a simple (albeit
patological) case that slips by Purify (using Purify 3.0 with g++
version 2.6.3 under Solaris 2.3):

    Script started on Fri Jun 16 09:55:03 1995
    billf@mothra:/u2/billf% cat foo.cc

    #include <malloc.h>
    #include <stdio.h>

    main()

    {
	char* cp = (char*) malloc(240);
	printf("%x\n", cp);
	free(cp);

	for (int i = 0; i < 100; i++)
	    free(malloc(240));

	int* ip = (int *) malloc(60 * sizeof(int));
	printf("%x\n", ip);

	ip[0] = 37;
	strcpy(cp, "hello");	// This is wrong, and Purify doesn't catch it
	printf("I bet this isn't 37:  %d\n", ip[0]);

	free(ip);
    }

    billf@mothra:/u2/billf% purify g++ -g foo.cc
    Purify 3.0 Solaris 2, Copyright 1992-1994 Pure Software Inc.
    Instrumenting: cca003Ku1.o Linking

    billf@mothra:/u2/billf% a.out
    5c080
    5c080
    I bet this isn't 37:  1751477356

Here's what Purify had to say about this program run:

   Finished  a.out                (   0 errors,    0 leaked bytes)
      Purify instrumented a.out (pid 13632 at Fri Jun 16 09:55:25 1995)
      Current file descriptors in use: 5
      Memory leaked: 0 bytes (0%); potentially leaked: 0 bytes (0%)
      Program exited with status code 0.

The trick here is mallocing and freeing 240 bytes 100 times.  That causes
the int* malloc to land at the same place the char* malloc did, thus
fooling Purify into thinking that the "strcpy(cp, "hello")" call is
kosher.

I admit that this is a bit of a pathological case, but it does illustrate
a point:  Even the best of tools can't catch everything, particularly when
built on top of an unsound foundation.


Here are some less pathological, real-world examples of memory problems
in C/C++ where Purify won't help:

    *  You're using a third-party library that implements its own memory
       pools on top of malloc().  It malloc's (relatively) large chunks
       of memory at a time, and parcels these chunks out to its clients.
       
       As far as Purify can tell, a whole region of memory has been
       malloc'd.  If you (or worse, the third-party library) "frees"
       an object back to the pool, Purify has no way of knowing, so it
       won't detect writes to this freed object.
    
    *  You get "lucky", and the regression tests that you run don't tickle
       the bug when you're running under Purify.  Your clients (who are running
       a non-debug version of your app) aren't so lucky.
    
    *  The error only happens on a platform where you don't have Purify
       (like Windoze -- and, to paraphrase Al Gore, I've used Purify,
       and Bounds Checker, you're no Purify).

Besides these kinds of debugging issues, there's a fundamental advantage
that a real GC'd framework has over C++ with Purify:  You don't have to
manage the memory yourself.  Sure, Purify can tell you where you allocated
an object that never got freed, but it can't tell you where you were supposed
to free it.  Sometimes this is obvious, and sometimes it's very difficult
indeed.

Handling the memory management in any non-trivial C++ project takes work, 
and that's work that you simply don't have to do if you have GC.  Much of 
this work comes about because manual memory management tends to break 
encapsulation:  You, the client of some other object, have to worry 
about whether you or it own any piece of memory that you get from it.

>Ok, you may have to spend a few additional hours after a week of 
>programming

It's a lot more work than that to design the memory management protocols
that you need for an even moderately complex application, and those protocols
tend to be fragile in the face of change.

> <...>
>But once you have managed to get there and you have collected
>or written your favorite class libraries you get some benefits
>from your effort - writing good object oriented in code C++ is 
>surely as convenient as in other OO languages (Well, Smalltalk's
>Blocks are missing if you are used to them, but thats all), 

Blocks, GC, generic containers, meta-information, quick development
turnaround (i.e. no more waiting for make), pointer safety (i.e.
no casts), good tool support, etc.

> <...>
>Each system has it's advantages and disadvantages 
>which have to live with when using it. (I can tell it from
>C++ and Smalltalk since I use them both.)

No argument here...  C++ is, IMHO, a fine language for many things.
It definitely has advangages over Smalltalk (static typing, smaller
footprint (at least for small apps), and the plethora of tools
available for it come to mind).  I also think that it has a number
of fundamental problems that aren't going to be fixed any time
soon.  One of the big problems is memory management, and while Purify
is a wonderful tool, and is a great help, it doesn't "fix" it.

>No reason for any flame wars... ;-)

No flame intended :-)
--
Bill Foote                | Adde parvum parvo magnus acervus ecrit.
billf@medicus.com         | [Add little to little and there will be a big pile]
Medicus Systems           |    -- Ovid, via Frederick P. Brooks, Jr.
Alameda, CA USA           |
