Frage

Der folgende Code zeigt ein seltsames Problem, das ich in einem Turbo C ++ Explorer Projekt. Einer der drei Stapel Objekte in D :: D () wird nach geht out of scope nicht zerstört.

Dies geschieht nur, wenn im Release-Modus kompiliert, die auto_ptrs a_ und b_ sind von verschiedenen Arten und die Ausnahme ausgelöst erbt nicht von std :: exception. Es scheint in VC zu arbeiten ++ 2005 und C ++ Builder ganz gut 2009 ich die BDS2006 Update 2 nicht installiert habe, den Hotfix-Rollup und Hotfix-12.

Ist es mein Code oder der Compiler? Wissen Sie, ob ein Update? Nicht zuverlässig in der Lage, auto_ptr in einem VCL-Projekt zu verwenden wäre sehr unbequem sein.


#include <memory>
#include <stdexcept>
#include <iostream>

typedef std::exception my_error; // will work fine if replaced with line below
//class my_error : public std::exception {};

class A {};
class B {};

class C
{
public:
    C(int id) : id_(id) { std::cout << "C::C() " << id_ << std::endl; };
    ~C() { std::cout << "C::~C() " << id_ << std::endl; };
private:
    int id_;
};

class D
{
public:
    D()
    {
        C c1(1);
        C c2(2);
        C c3(3);

        throw my_error();
    };

private:
    std::auto_ptr<A> a_;
    std::auto_ptr<B> b_; // will work fine if replaced with line below
//  std::auto_ptr<A> b_;
//  std::auto_ptr<C> c_; // see expected output
};

#pragma argsused
int main(int argc, char* argv[])
{
    try
    {
        D d;
    }
    catch (...)
    {
        std::cout << "caught exception" << std::endl;
    }

    return 0;
}


Erwartet:

C::C() 1
C::C() 2
C::C() 3
C::~C() 3
C::~C() 2
C::~C() 1
caught exception


Haben Sie:

C::C() 1
C::C() 2
C::C() 3
C::~C() 2
C::~C() 1
caught exception


Got (mit Linie '// std::auto_ptr<C> c_;' unkommentiert):

C::C() 1
C::C() 2
C::C() 3
C::~C() 1
caught exception


Edit: Aus vorgeschlagenen Änderungen
Edit 2:
Getestet habe ich es nur mit C ++ Builder 2007 (11.0.2902.10471), die das gleiche Problem zeigt. Die Freigabe Konfiguration funktioniert, sobald ich die „Debug-Informationen“ Box im Projekt überprüfen -> Optionen -> C ++ Compiler -> Debuggen. Es überrascht mich, dass die ausführbare Datei kleiner mit „Debug-Informationen“ wird aktiviert (bis zu 31,5 KB von 39,5 KB).
Bearbeiten 3:
In Turbo C ++ Explorer (C ++ Builder 2006) (10.0.2288.42451) die Freigabe Konfiguration funktioniert, wenn ich die "Inline Funktionserweiterung (-VI)" -Box im Projekt deaktivieren -> Optionen -> C ++ Compiler -> Debuggen. Ersetzen die erste Zeile (#include <memory>) mit dem folgenden Code macht es auch funktionieren.

#pragma option push -vi-
#include <memory>
#pragma option pop 
War es hilfreich?

Lösung

Dies scheint ein Compiler Fehler zu sein. Ich lief die gleiche Probe in VS2008SP1 und bekam die erwartete Ausgabe.

Andere Tipps

Für was es wert ist, GCC 3.4.6 tut die erwartete Sache:

$ g++ main.cpp

$ a.out
C::C()
C::C()
C::~C()
C::~C()
caught exception

Es ist ein Compiler Fehler in C ++ Builder 2006 C ++ Builder 2009 behebt es; dies ist der Ausgang I für BCC v6.1 bekommen:

C::C() 1
C::C() 2
C::C() 3
C::~C() 3
C::~C() 2
C::~C() 1
caught exception

Wenn eine Ausnahme in einem Objekt Konstruktor geworfen wird, wird der Destruktor nicht ausgeführt werden.

Der Compiler hat keine Möglichkeit zu wissen, ob der Konstruktor ausreichend für den destructor abgeschlossen korrekt funktionieren.

Siehe http://www.parashift.com/ c ++ - FAQ-lite / exceptions.html # faq-17.4

EDIT: unten auf den Kommentar reagieren ... In diesem Fall ist es sehr wahrscheinlich, ein Compiler Fehler Verklumpen der Regel ‚nicht den destructor läuft‘ mit falsch keine Gegenstände auf dem Stapel zu zerstören.

Vielleicht wird der Stream Cout nicht gespült? Können Sie stattdessen mit cerr versuchen? oder direkt einen Haltepunkt in destructor setzen und prüfen, ob sie getroffen werden?

ich dies nur auf der freien Kommandozeilen getestet bcc5.5.1 und C ++ Builder 6 bcc5.64 und beide wie erwartet - was für eine Überraschung, wenn man bedenkt, wie alt sie sind. Dann habe ich versucht, dies in C ++ Builder 2007, bcc5.93 und der Fehler ist dort vorhanden. In der Tat könnte der Beispiel-Code auf primitive Typen vereinfacht werden und der Fehler würde noch vorhanden sein:

class D
{
public:
    D();

private:
    std::auto_ptr<int>      a_;
    std::auto_ptr<short>    b_;
    std::auto_ptr<char>     c_;
    std::auto_ptr<bool>     d_;
};

Das extremste Beispiel endet verursacht keine der die entsprechenden destructor für Klasse C bezeichnet werden! Wenn Sie in der Diagnose dieser Fehler interessiert sind weiter, ein Trick, den Sie durchführen können, ist eine Montagebreakpoint in Ihrem D :: D () Ctor einzufügen:

// Note that D::D() ctor can't be inlined if it contains assembly
// limitation of borland compilers unfortunately
D::D()
{
    __asm int 3;
    C c1(1);
    C c2(2);
    C c3(3);

    throw my_error();
}

Sie würden dann lassen Sie es durch den Debugger ausführen. Wenn die Ausführung erreicht, dass angegebenen Haltepunkt wird das Programm beenden und die Steuerung wird an den Debugger werden übertragen zurück. Sie können dann einzelne Schritt durch die Anordnung zu sehen, wo das Problem liegt.

Sieht aus wie ein Fehler in der Ausnahmebehandlung Stapel Abroll-Code. Versuchen Sie, eine einfache Klasse E mit einer Instanz in D's Konstruktor machen und sehen, ob es aufgerufen wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top