Fehler in "How not to program in c++"?



  • Ich behaupte, dass die Erklärung für den Fehler falsch ist, das einzige was hier nicht definiert ist, ist die Ausgabe vom d'tor, da cout ja durch nifty-initialization bei der ersten Verwendung initialisiert wird.

    A student of C++ wanted to see how constructors and destructors were called, so he wrote the following program. Yet he learned more than he bargained for. What's the problem?

    1 /************************************************
    2 * Class tester. Test constructor / destructor*
    3 * calling. *
    4 /
    5 #include <iostream>
    6
    7 /

    8 * tester -- Class that tells the world when *
    9 * it's created and destroyed. *
    10 ************************************************/
    11 class tester {
    12 public:
    13 tester(void) {
    14 std::cout <<
    15 "tester::tester() called\n";
    16 }
    17 ~tester(void) {
    18 std::cout <<
    19 "tester::~tester() called\n";
    20 }
    21 };
    22
    23 static tester a_var; // Variable to test with
    24
    25 int main()
    26 {
    27 std::cout << "In main\n";
    28 return (0);
    29 }

    The problem is that the initialization order of global variable is not guaranteed. In this case, a_var assumes that std::cout is initialized. That may not be the case.

    Let's assume the worse and assume that the initialization order is a_var, std::cout. In that case, a_var is created. The constructor is called and output a message to std::cout. Because std::cout has not been created yet, things get very confused and the program crashes.



  • Korrektor schrieb:

    Ich behaupte, dass die Erklärung für den Fehler falsch ist, das einzige was hier nicht definiert ist, ist die Ausgabe vom d'tor, da cout ja durch nifty-initialization bei der ersten Verwendung initialisiert wird.

    wenn der ctor von cout vorher ist, dann ist auch der dtor von cout nachher. die zu löschenden objekte liegen nämliche auf nem stack (als verkettete liste vermutlich).

    damit ist da gar kein fehler.



  • sein stil ist ungewöhnlich, finde ich

    1 /************************************************ 
    2 * Class tester. Test constructor / destructor* 
    3 * calling. * 
    4 ************************************************/ 
    //naja, wer's braucht
    
    5 #include <iostream> 
    //warum kein usine namespace std;?
    
    6 
    7 /************************************************ 
    8 * tester -- Class that tells the world when * 
    9 * it's created and destroyed. * 
    10 ************************************************/ 
    //hat er schonmal gesagt
    
    11 class tester { 
    12 public: 
    //struct?
    
    13 tester(void) { 
    //(void) ist aber voll veraltet
    
    14 std::cout << 
    15 "tester::tester() called\n"; 
    16 } 
    17 ~tester(void) { 
    //dito
    
    18 std::cout << 
    19 "tester::~tester() called\n"; 
    20 } 
    21 }; 
    22 
    
    //ist deprecated
    23 static tester a_var; // Variable to test with 
    24 
    25 int main() 
    26 { 
    27 std::cout << "In main\n"; 
    
    //return ist keine funktion und war nie eine. weg mit den klammern
    28 return (0); 
    29 }
    

  • Mod

    Korrektor schrieb:

    Ich behaupte, dass die Erklärung für den Fehler falsch ist, das einzige was hier nicht definiert ist, ist die Ausgabe vom d'tor, da cout ja durch nifty-initialization bei der ersten Verwendung initialisiert wird.

    wir wissen nicht wirklich wie cout konstruiert wird. der standard garantiert aber glücklicherweise, dass die lebenszeit der standard-iostream-objekte hinreichend lang ist, um in konstruktoren und destruktoren statischer objekte verwendet werden zu können (27.3./2 und Fußnote 265). das verhalten ist hier also tatsächlich wohldefiniert.



  • volkard schrieb:

    //warum kein usine namespace std;?

    Weil Du damit den Sinn von Namespaces wieder aushebelst?
    Ok bei solch einfachen Beispielen kein Problem, aber lass das nicht zur Gewohnheit werden in grösseren Projekten.



  • 1310-Logik schrieb:

    volkard schrieb:

    //warum kein usine namespace std;?

    Weil Du damit den Sinn von Namespaces wieder aushebelst?

    Blödsinn. Der Sinn von Namepsaces ist nicht dich zur Eingaben von Präfixen zu zwingen und damit das Karpaltunnelsyndrom schneller zu verbreiten. Namespaces helfen Entitäten zu gruppieren und Namenskonflikte zu vermeiden und zwar über große/verschiedene Projekte hinweg.

    Lokal innerhalb einer cpp-Datei hat man aber volle Kontrolle über alle Namen. Man muss sich hier also nicht vor Namenskonflikten fürchten. Insofern kann man hier auch problemlos alle Namen eines Namespaces über eine using-Direktive verfügbar machen und sich die Präfixe sparen. Das ist einfach eine Frage des persönliches Gechmacks. Diese Form der Bequemlichkeit findet in der Sprache an einigen Stellen sogar ohne using-Dirketiven/Deklarationen statt - siehe ADL. Argument wie: " using-Direktiven führen dazu, dass ich nicht mehr bei jeder Funktion weiß, aus welchem Namespace sie kommt" gelten also nicht, da dies auch für Code ohne usings gilt.

    Das Gesagte gilt natürlich nur für usings innerhalb von cpp-Dateien nach allen includes.


Anmelden zum Antworten