Thread View: comp.std.c++
5 messages
5 total messages
Started by JdeBP
Sat, 11 Nov 1995 04:37
Re: Global Init/Shutdown: A solution (hopefully)
Author: JdeBP
Date: Sat, 11 Nov 1995 04:37
Date: Sat, 11 Nov 1995 04:37
78 lines
4665 bytes
4665 bytes
Eugene Radchenko (eugene@qsar.chem.msu.su) wrote: : I think it can be solved by requiring that this initialization : really happens 'just' before the objects/functions in it are first accessed : - which may even happen before main() - when exactly is unimportant. If the : hardware architecture & OS support virtual memory [...] I really don't think that the thousands of programmers who daily program for operating systems that do not support virtual memory will happily let ISO get away with defining the C++ language so that a conforming implementation is not possible on their machines. Incidentally, if what you are suggesting is what I think that you are suggesting, you are imposing an implementation overhead that most people will find unacceptable, since every object with static storage duration would have to reside in a separate page. That is unless you were going for translation-unit granularity, in which case the "Deadly Embrace Initialisation", where the initialisation of object A in translation unit X references object B in translation unit Y and the initialisation of object C in translation unit Y references object D in translation unit X, becomes a problem once more (which translation unit do you initialise first ?) and you haven't solved the global initialisation problem at all. : If a unit is not referenced, it would not be : constructed. Maybe it is really a desirable behavior (although draft : standard says otherwise ;). I don't want any such behaviour. I rely on static duration instances of single-instance classes to model libraries in DLLs. The objects are not themselves referenced, but the constructors and destructors perform library initialisation and cleanup. I usually put the instances in their own translation unit, along with _DLL_InitTerm(), as well. Your proposed alteration would break my programs, and, worse, leave me with no practical alternative to achieve the same ends. : Also, I think that the lifetime of the local static objects and global : translation units (i.e. sets of global objects defined in them) should : conform to the single stack-like semantics (actual implementation data : structure may vary). In other words, the object/unit is 'pushed' when its : construction starts (or ends). At the implementation-dependent moment after : main() returns, the implementation shutdown code starts 'popping' : objects/units from the stack and calling the appropriate destructors. Although not implemented as a stack, you will find that many implementations already do this, because one favourite means of implementing global initialisation is to construct at link time a list of all static duration objectsi from all translation units and bind them into the program. At runtime this list is traversed from one end to the other to perform dynamic initialisation, and in the reverse direction to perform destruction. Of course, a stack allows you to defer the ordering of the elements in the list to run-time. The main problem with global initialisation is that it is very hard to describe in English the order in which the objects in a program should be initialised, especially when individual translation units cannot know how many other translation units will comprise the whole program, and what static duration objects they will require. So it's doubly hard to describe it in a computer language. The insight into implementation above may reveal a direction to pursue, however. If the total number of static duration objects in the whole program is only known at link time, then the mechanism for controlling the relative ordering amongst translation units belongs with the linker. ( Of course the C++ Working Paper has only a peripheral notion of a linker, and no way to control it at all. I suspect that you'd have a hard time persuading people to come up with a standard mechanism for communicating directives to the linker from within the C++ language. ) --- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu. Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Global Init/Shutdown: A solution (hopefully)
Author: J. Kanze
Date: Mon, 13 Nov 1995 13:01
Date: Mon, 13 Nov 1995 13:01
81 lines
4279 bytes
4279 bytes
JdeBP@jba.co.uk wrote:
|> : Also, I think that the lifetime of the local static objects and global
|> : translation units (i.e. sets of global objects defined in them) should
|> : conform to the single stack-like semantics (actual implementation data
|> : structure may vary). In other words, the object/unit is 'pushed' when its
|> : construction starts (or ends). At the implementation-dependent moment
|> : after main() returns, the implementation shutdown code starts 'popping'
|> : objects/units from the stack and calling the appropriate destructors.
|> Although not implemented as a stack, you will find that many
|> implementations already do this, because one favourite means of
|> implementing global initialisation is to construct at link time a list of
|> all static duration objectsi from all translation units and bind them into
|> the program. At runtime this list is traversed from one end to the other
|> to perform dynamic initialisation, and in the reverse direction to perform
|> destruction.
This is, in effect, what most implementations do. By my reading of the
standard, however, it is *not* legal. Given the following program (in
which all types with capital letters are classes with constructors and
destructors):
extern int f() ;
A a1 ;
int a2 = f() ;
A a3 ;
int
f()
{
static A a2a ;
return 0 ;
}
int
main()
{
return 0 ;
}
According to 3.6.2, the static objects will be initialized in the order
a1, a2/a2a, a3. (The initialization of a2 encompasses the
initialization of a2a.) Thus, applying the rule from 3.6.3:
``Destruction [of static objects] is done in reverse order of
initialization'', the destructors must be called in the reverse order:
a3, a2a, a1. In practice, this requires some sort of stack-like list,
since most compilers will not do enough flow analysis to determine the
exact order. (In fact, I do not believe they can. The static variable
in f() could be in a block goverened by an if whose condition depended
on the result of a call to getenv, for example.)
Note that in 3.6.3, the rule very definitly applies to ``static
objects''. Given that in the preceding section (3.6.2), the notation of
``nonlocal static objects'' occurs consistently when local static
objects are not considered, I do not think one can attribute this to
carelessness on the part of the committee; IMHO, the intent is clear.
Another interesting case:
A a1 ;
A a2 ;
A a3 ;
// ...
The constructor of a2 throws an exception (not caught, of course). In
no case can the compiler be allowed to call the destructor to a3. All
of the compilers I've tested do. Which in practice means that you
cannot safely let an exception escape from a constructor unless you can
guarantee that the type can never be used as a static variable with file
scope. (Gee, and I always thought that one of the main reasons for
using exceptions was error reporting from constructors.)
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Global Init/Shutdown: A solution (hopefully)
Author: Herb Sutter
Date: Tue, 14 Nov 1995 02:17
Date: Tue, 14 Nov 1995 02:17
38 lines
2494 bytes
2494 bytes
In article <4873sc$hum@gabi.gabi-soft.fr>, kanze@gabi-soft.fr (J. Kanze) wrote: >Another interesting case: > > A a1 ; > A a2 ; > A a3 ; > // ... > >The constructor of a2 throws an exception (not caught, of course). In >no case can the compiler be allowed to call the destructor to a3. All Or a2 for that matter, at least not according to C++PL2 sec 9.4.1 par 2. >of the compilers I've tested do. Which in practice means that you >cannot safely let an exception escape from a constructor unless you can >guarantee that the type can never be used as a static variable with file >scope. (Gee, and I always thought that one of the main reasons for >using exceptions was error reporting from constructors.) Trying the above under BC++ 4.52, A::A() is called twice and then A::~A() is called once, which is correct. Just out of curiosity, what compilers acted improperly? Pls. email the answer if this is drifting off-topic for c.s.c++. Thanks. [Moderator's note: personally I'd be inclined to say that discussion of which compilers are standard-conforming in some particular respect is appropriate for comp.std.c++. If anyone has any comments or suggestions about the moderation policy, please send them to std-c++-request@ncar.ucar.edu. -fjh.] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184 Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019 --- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu. Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Global Init/Shutdown: A solution (hopefully)
Author: Herb Sutter
Date: Wed, 15 Nov 1995 17:49
Date: Wed, 15 Nov 1995 17:49
44 lines
2457 bytes
2457 bytes
In article <9511141105.AA01230@lts.sel.alcatel.de>, James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> wrote: >|> >Another interesting case: >|> > >|> > A a1 ; >|> > A a2 ; >|> > A a3 ; >|> > // ... >|> > >|> >The constructor of a2 throws an exception >|> Trying the above under BC++ 4.52, A::A() is called twice and then A::~A() >|> is called once, which is correct. > >The only compiler I have access to that supports exceptions is Sun CC >4.0.1; this is the compiler I used for my initial tests. I modified >the test to call exit, instead of throwing an exception, and got the >following results: > > ctors dtors > Sun CC 4.0.1 (w/ exceptions) 2 3 > Sun CC 2.1 2 0 > Cfront 3.0.1 (direct port, not from Sun) 2 3 > g++ 2.6.3 2 0 > g++ 2.7.0 2 0 Hold on... you changed the question! :-) If I modify my BC++ 4.52 program to call exit() (instead of throwing) in a2's ctor, I get the incorrect result of three A::~A() calls. If I change it to call abort() in a2's ctor, I get zero A::~A()s. Does the WP specify what/how dtors should be called in the case of an exit() or abort()? Herb ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184 Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019 [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu. Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Global Init/Shutdown: A solution (hopefully)
Author: J. Kanze
Date: Fri, 17 Nov 1995 00:41
Date: Fri, 17 Nov 1995 00:41
55 lines
3273 bytes
3273 bytes
Herb Sutter (herbs@interlog.com) wrote:
|> In article <9511141105.AA01230@lts.sel.alcatel.de>,
|> James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> wrote:
|> >|> >Another interesting case:
|> >|> >
|> >|> > A a1 ;
|> >|> > A a2 ;
|> >|> > A a3 ;
|> >|> > // ...
|> >|> >
|> >|> >The constructor of a2 throws an exception
|> >|>
|> >|> Trying the above under BC++ 4.52, A::A() is called twice and then
|> >|> A::~A() is called once, which is correct.
|> >
|> >The only compiler I have access to that supports exceptions is Sun CC
|> >4.0.1; this is the compiler I used for my initial tests. I modified
|> >the test to call exit, instead of throwing an exception, and got the
|> >following results:
|> >
|> > ctors dtors
|> > Sun CC 4.0.1 (w/ exceptions) 2 3
|> > Sun CC 2.1 2 0
|> > Cfront 3.0.1 (direct port, not from Sun) 2 3
|> > g++ 2.6.3 2 0
|> > g++ 2.7.0 2 0
|> Hold on... you changed the question! :-) If I modify my BC++ 4.52 program
I had to. The Cfront based compilers and g++ don't support exceptions!
|> to call exit() (instead of throwing) in a2's ctor, I get the incorrect
|> result of three A::~A() calls. If I change it to call abort() in a2's
|> ctor, I get zero A::~A()s.
|> Does the WP specify what/how dtors should be called in the case of an
|> exit() or abort()?
Yes and no. In the case of abort, it is explicit: no destructors are
called. In the case of exit... I can find no statement forbidding
calling exit from a constructor, or saying that it is undefined
behavior. So one must suppose that it is permitted. But calling a
destructor on an uninitialized object will forceably result in undefined
behavior. Whence I conclude that an implementation may not generate
code which does so *unless* my program already contains undefined
behavior.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads