🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #3375

Re: Portability. Modules. WAS: RE: Are all Windows programs ill-formed?

#3375
From: James Kanze US/ESC 60/3/141 #407...
Date: Tue, 20 Feb 1996 18:56
132 lines
7724 bytes
In article <UPMAIL04.199602192354280583@msn.com> "Eugene Lazutkin"
<INT@msn.com> writes:

|> On 	Tuesday, February 13, 1996 7:48 AM, 	
|> 	James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> wrote:
|> > In article <01BAF61B.3131B100@dino.int.com> Eugene Lazutkin
|> > <eugene@int.com> writes:

|> > The oldest one, rarely used except for the simplest cases today, is to
|> > design the list such that the initial initialization to 0 is adequate,
|> > and give it a special no-op constructor.  Thus, for example, my
|> > command line parser class maintains a list of options (staticly
|> > declared objects); a NULL pointer signifies an empty list, and the
|> > constructor does nothing.  Thus, it doesn't matter if the options are
|> > constructed (and register themselves) before the list.

|> It doesn't help to create a simple double-linked ring.  Not all 
|> containers can be built on a single-linked list or a tree structure.
|> E.g., any member of a double linked ring can exclude itself from the 
|> list automatically by its destructor at any time.  You can't do it
|> with single-linked list or with double-linked list (not ring).

I've used it for double-linked lists:-).  It does mean 1) that the
list itself is special, and 2) a little bit more code to check the
special case (linked to head/tail).  In the case of 1, this is
generally the case anyway.  For 2, in the cases I've used it,
performance hasn't been a problem.

More generally, most of the classes I have that use this are
associative arrays.  The actual array is dynamically allocated (on the
heap), and the only static data is a pointer.  The access routines
check for NULL, and create the array as needed.

|> BTW, who frees the allocated memory?  When?  How can I specify the 
|> order of destruction?  ObjectSpace's STL has problems with that.
|> The program using this STL will leak.  They can't eleminate this 
|> problem.  OK, they have a work around.  But it is very inefficient:
|> they use per-object allocators instead of per-class.

Order of destruction is undefined.  In general, IMHO, destructors
shouldn't be doing much, so that order of destruction is not a
significant problem.

In most cases of static maps, I simply let the memory leak.  Since I
couldn't free it before the static destructors run anyway, there's
really no point; once the process finishes, the OS recovers it anyway.
(I know that this isn't particularly elegant, but solving real
problems has had priority until now.)

A potential solution would have the users of the class enrol/deenrol.
When the last user deenrols, clean up.

|> > The more frequent solution today is to have a function returning a
|> > reference to a local static object.  The object will be constructed
|> > the first time the function is called.  The enrolment functions in the
|> > Item's call the function to get the actual list object.

|> Does this static object have any constructors?  Or its components?
|> Is it based on some class without constructors?  If not, who will
|> be initialize it?  And how?  Who will deinitialize it?  A lot of
|> problems.

Of course, it has constructors.  And destructors.  The constructors
are called the first time the function is called.  Note that this is
the only solution (that I know of, at least) that is fully conforming,
and works even if the implementation does not initialize everything
before main.

There may still be problems with order of destruction.  According to
the current draft (Jan. 96), all static objects (including those with
block scope) must be destructed in the reverse order of their
construction, so there is at least one guarantee, although probably
not the one you need, at least presuming that order of construction
refers to the order the constructors were entered, and not the order
they were left.

Note that most compilers do not yet implement this order of
destruction.  If I remember right, for example, the Sun compiler
(4.0.1) will destruct all file (namespace) scope static objects first,
and then block scope statics.

|> Of course, both these solutions work just fine in certain specific 
|> cases.  But it is not a generic answer.  It is a trick.

I'll accept this for the first solution.  I only use it in special
cases, and in modern code, practically not at all.  The second
solution is not a trick, however; it is the standard generic answer,
which works in all cases, and ensures destruction.  It may lead to
problems in the order of destruction, but no more than any other
solution.  The best solution here is to not allow destructors to
access *other* static objects.

|> > I often encapsulate the above solution in a SharedList interface
|> > class.  All instances of the SharedList actually refer to the same
|> > list object.  The SharedList only contains a pointer to the actual
|> > list object, and forwards all requests to it.  The pointer is
|> > initialized by calling the function above in the constructor.
|> > 
|> > |> Alternative way: include all items into the container manually and
|> > |> don't forget to do this initialization every time when you use this
|> > |> container in your program.
|> > 
|> > This is extremely error prone (as you also point out).  If you are
|> > willing to accept that all of the objects are known in the same
|> > compilation unit, you might as well define them there, and let the
|> > guaranteed order of construction within the compilation unit do the
|> > trick.

|> This is C++, not Pascal.  We have separate units.  I think it is too
|> strong requirement to put some logically different items together.
|> I think it is too error-prone.

I basically agree, although if the objects aren't related in any way,
then the order of construction between them shouldn't matter:-).  In
fact, of course, I use the registry idiom in almost all cases where I
have something to parse, including the command line options.  I find
it nice that the option is declared near its point of use, and that no
other code (including main) knows about it.  I also find it nice that
I can add a command to a parser without changing a single line of
existing code.
-- 
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
                -- A la recherche d'une activiti dans une region francophone
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std.c++-request@ncar.ucar.edu 
]
Technical Details
Message-ID: <KANZE.96Feb20112203@slsvewt.lts.sel.alcatel.de>
Path: arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austern
References: <UPMAIL04.199602192354280583@msn.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austern
From: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Newsgroups: comp.std.c++
Subject: Re: Portability. Modules. WAS: RE: Are all Windows programs ill-formed?
Date: 20 Feb 1996 10:56:30 PST
Organization: GABI Software, Sarl.
Approved: austern@isolde.mti.sgi.com
Message-ID: <KANZE.96Feb20112203@slsvewt.lts.sel.alcatel.de>
References: <UPMAIL04.199602192354280583@msn.com>
NNTP-Posting-Host: isolde.mti.sgi.com
X-Original-Date: 20 Feb 1996 10:22:03 GMT
In-Reply-To: "Eugene Lazutkin"'s message of 20 Feb 96 07:15:52 GMT
Apparently-To: std-c++@ncar.ucar.edu
X-Auth: PGPMoose V1.1 PGP comp.std.c++
 iQBVAwUBMSoZaEy4NqrwXLNJAQHwXQH8D3tdSLEn2dG6HcMayOcHKlXcBVR0+Xzm
 0yqKrmHA6OQwSFuMK7vk/PNu4DpWVsaCoROz4gAuCH9pX/j53xCagg==
 =+v5v
Originator: austern@isolde.mti.sgi.com