Benutzer:Rdiez/HowToWriteMaintainableInitialisationAndTerminationCode: Unterschied zwischen den Versionen

Aus /dev/tal
Wechseln zu: Navigation, Suche
(Weiterleitung nach Benutzer:Rdiez/PageRemoved erstellt)
 
Zeile 1: Zeile 1:
{{BenutzerSeitenNichtVeraendernWarnung|rdiez}}
+
#REDIRECT [[Benutzer:Rdiez/PageRemoved]]
 
+
= How to write maintainable initialisation and termination code =
+
 
+
The traditional, C-style way is still the best one:
+
 
+
int main ( int argc, char * argv[] )
+
{
+
  InitA();
+
  InitB();
+
  InitC();
+
  ...
+
  create some threads
+
  ...
+
  do some work
+
  ...
+
  wait for thread termination
+
  ...
+
  FiniC();
+
  FiniB();
+
  FiniA();
+
 
+
  // Here you can check for memory and file descriptor leaks.
+
 
+
  return whatever;
+
  }
+
 
+
Don't over-engineer it! The method above is not cool, but is perfectly adequate. It's
+
easy to understand and to maintain. Sometimes it can be tricky to find the right
+
initialisation order, but then it will be explicitly described, and above all,
+
it will remain the same no matter what the other code does.
+
 
+
The only real drawback is that, if you have different applications/programs,
+
you need to write a new version of the above for each one,
+
and probably most of it will be copy-paste duplication. But that is a minor inconvenience.
+
 
+
== Do not define global or static object instances, use pointers instead ==
+
 
+
Global or static object instances generate constructor calls that are executed before main(),
+
and that may be too early, if not today, then probably in the future.
+
 
+
Besides, singleton objects tend to use other global, singleton objects, and the initialisation order
+
of such objects is not guaranteed in the C standard. The order in which the constructors are called may depend
+
on your operating system, on your compiler version, or even on the order in which the object modules
+
are listed on your makefile (the order in the linker command line).
+
 
+
If you want to reuse the code in an embedded application, you may find it difficult to control
+
the initialisation order, especially since it is often poorly documented or hard to adapt.
+
For example, think about the PowerPC EABI, which injects a hidden __eabi() call in
+
main() in order to initialise C++ exception support and so on. Say you want to use your own
+
memory allocator and __eabi() is calling some C++ constructors before your code runs:
+
you'll have to learn much more about EABI and about the C runtime initialisation than you ever wanted to.
+
 
+
If you need to move the code to a Windows DLL or to a Unix Shared Object at a later point in time, you will have to rewrite the initialisation logic anyway.
+
 
+
Therefore, always use global or static pointers, and let them be NULL on start-up, then follow the initialisation method described above:
+
 
+
  CreateSingletonA();
+
  CreateSingletonB();
+
  ...
+
  GetSingletonA()->UseIt();  GetSingletonB()->UseIt();  ...
+
  GetSingletonA()->UseIt();  GetSingletonB()->UseIt();  ...
+
  ...
+
  DestroySingletonB();
+
  DestroySingletonA();
+
 
+
== Do not initialise global singletons on first touch ==
+
 
+
Unless you really need the performance improvement that lazy initialisation may provide, avoid
+
using such an object creation pattern:
+
 
+
  MyClass * GetSingleton ( void )
+
  {
+
    static MyClass obj;
+
    return &obj;
+
  }
+
 
+
Reasons to avoid it are:
+
 
+
* The function above may not be thread-safe on all platforms, especially on embedded targets.
+
* The destructor will run after main(), making memory leak detection difficult. <br/> An error during destruction may need to be logged, but the logger object may have been destroyed already.
+
* The destruction order for such objects is not specified, not portable, etc. <br/> At some point in the future, you may need to destroy some other singleton beforehand, and that's impossible to do in a portable way.
+
* The initialisation order will depend on the code that uses the singletons. <br/> If the usage pattern changes, the object may initialise too early or too late. It is not immediately obvious that moving a call to GetSingleton() may change the initialisation or destruction order.
+
 
+
== Forget about atexit() and friends ==
+
 
+
You'll have a hard time trying to control the destruction order in a portable manner. Some embedded platforms do not have atexit() support.
+

Aktuelle Version vom 22. März 2015, 20:17 Uhr

Weiterleitung nach: