Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Objektkonstruktion bei Erweiterung STL-Containers mit push_back

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
26.04.2005, 11:27 Uhr
GateKeeper



Hallo Leute,

Um es gleich vorwegzunehmen: Dies ist eine Frage für alle, die sich gut mit der STL auskennen und mit Templates. Die überflüssigen Teile der Quellcodes habe ich rausgenommen, damit die Fragestellung übersichtlich bleibt.

Ich habe ein Klassen-Template game_object_manager, eine Klasse billard_sphere und eine Klasse trace_obj.

game_object_manager.h:

C++:

template <class GameObjectType>
class game_object_manager
{

private:
    
    vector<GameObjectType> v_Objects ;

    int ObjectNumber ;
    int CurrentObject ;

public:

    game_object_manager() ;

    void New_Object(void) ;
    GameObjectType *Get_Current_Object(void) ;

} ;




billard_sphere.h:

C++:

class billard_sphere
{
private:

    trace_obj Debug ;

    float Mass, Radius, VelSum ;

    const billard_boundary* FeldDerKugel ;

public:

    vec3 Pos, Vel ;

    billard_sphere(float cx, float cy, float cz, float Mass, float Radius) ;
    billard_sphere(void) ;

} ;





trace_obj.h:

C++:

class trace_obj
{
private:

#ifdef _PME_DEBUG

    char szDescriptor[ VARTRACE_DESCRIPTOR_SIZE ] ; // Name Of Object
    time_t    StartTime ;
    trace_var* Members ; // All Member-Vars
    debug_out* Display ; // Debug-Output object
    
#endif

public:

    trace_obj(void) ;
    ~trace_obj(void) ;

    void Output(DBugEventType EventType, char* szInput) ;
    void Msg(char* szMessage, DBugDisplayMode DisplayMode) ;
    void Msg(char* szMessage) ;

} ;





Wie man sieht soll bei der Konstruktion einer neuen billard_sphere gleichzeitig ein trace_obj konstruiert werden (ist ja im Header von billard_sphere definiert). Dieses neue trace_obj gibt im eigenen Konstruktor wiederum eine NAchricht aus, dass und wann genau es erstellt wurde. Hier die Konstruktoren von trace_obj, lasst euch nicht irritieren vom Namespace, die Codeschnippsel oben wurden allesamt im Namespace "pme" definiert, das habe ich oben nur der Übersicht halber weggelassen:


C++:

pme::trace_obj::trace_obj(void)
{
#ifdef _PME_DEBUG
    
    // initialize
    memset( this->szDescriptor, 0, VARTRACE_DESCRIPTOR_SIZE );
    sprintf( this->szDescriptor, "Unbenannt" );
    
    // format output
    this->StartTime = time( NULL );

    // construct Display Object with Output-Type always:
    this->Display = new pme::debug_out(pme::CONSOLE,this->szDescriptor) ;

    // construct Members-Object if necessary:
    this->Members = NULL ;

        // ACHTUNG, HIER ERFOLGT DIE OBEN ANGESPROCHENE AUSGABE:
    this->Output(pme::BEGIN, NULL) ;

#endif
}




Wird eine billard_sphere zerstört, sollte ebenfalls der Member trace_obj zerstört werden. In diesem Fall wird der Destruktor von trace_obj aufgerufen. Er gibt eine Meldung aus, dass und wann das zugehörige Objekt zerstört wurde. Im folgenden der Destruktor von trace_obj:


C++:

pme::trace_obj::~trace_obj(void)
{
#ifdef _PME_DEBUG

    // format output
    this->Display->Output( pme::END, NULL/*as postfix*/, NULL) ;

        if (this->Members != NULL)    delete this->Members ;
    delete this->Display ;

#endif
}




Um nocheinmal zusammenzufassen: Bei der Erstellung eines billard_sphere-Objektes sollte der Konstruktor von trace_obj aufgerufen werden, bei der Zerstörung des Objekts sollte der Destruktor von trace_obj aufgerufen werden. Demnach müsste jeder Vorgang zu einer entsprechenden Nachricht führen.

Nun kommt die Template-Klasse game_object_manager ins Spiel (s.o.). Diese hat eine Member-Funktion "New_Object(void)" und genau diese Funktion funktioniert bei mir nicht so wie erwartet. Die Funktion ist wie folgt definiert:


C++:

template <class GameObjectType>
void game_object_manager<GameObjectType>::New_Object(void)
{
    // Ein neues Spielobjekt erstellen:
    GameObjectType NeuesObjekt ;
    this->v_Objects.push_back(NeuesObjekt) ;
    if (this->ObjectNumber > 0) this->CurrentObject++ ;
    this->ObjectNumber++ ;
}




In meinem Programm instantiiere ich game_object_manager explizit mit dem Typ billard_sphere. Danach erstelle ich ein neues billard_sphere-Objekt, indem ich die Memberfunktion New_Object() von game_object_manager aufrufe:


C++:

game_object_manager<pme::billard_sphere> AlleKugeln ;
    
AlleKugeln.New_Object() ;




Beim Aufruf von AlleKugeln.New_Object() ; hätte ich folgende Debug-Ausgabe erwartet:

1. eine BEGIN-Nachricht (weil ein neues Objekt billard_sphere erstellt wird)
2. noch eine BEGIN-Nachricht (weil das neue Objekt billard_sphere mit push_back() ans Ende des vektors kopiert wurde)
3. eine END-Nachricht (weil das in der Member-funktion New_Object() erstellte Objekt nun out of scope geht.

Nun bekomme ich aber nur folgende Debug-Ausgabe:


Code:

BEGIN Unbenannt time=1114507055
END Unbenannt time=1114507055 elapsed=0




Da kann ja wohl irgendwas nicht stimmen, denn laut dieser Debug-Meldung wird während des Ablaufs von New_Object() nur eine billard_sphere erstellt und wieder zerstört.

Ich bin euch für jeden noch so kleinen Tipp dankbar!

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
26.04.2005, 12:06 Uhr
Th



Die liegt an der Implementierung von vector bzw. dessen Member 'push_back'.
Bei einigen STL-Implementierungen wird eine bitweise Kopie gemacht (uninitialized_fill), statt den Konstruktor bzw. den Zuweisungsoperator aufzurufen.
Welche STL verwendest du denn? Schau mal einfach in die vector-Implementierung (da du dich ja mit templates auskennst, dürfte es kein Problem sein bzw. einfach beim Debuggen reinsteppen).
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
27.04.2005, 10:13 Uhr
GateKeeper



Hallo Th,

Danke für den Tipp ... mir war gar nicht klar, dass ich die STL-Implementierung einsehen kann dabei ist das ja in der Tat der beste Weg. Dort hab ich nun folgende Implementierung von insert gefunden (push_back() ist laut Implementierung nur insert am Ende des Vectors):


C++:

void insert(iterator _P, size_type _M, const _Ty& _X)
        {if (_End - _Last < _M)
            {size_type _N = size() + (_M < size() ? size() : _M);
            iterator _S = allocator.allocate(_N, (void *)0);
            iterator _Q = _Ucopy(_First, _P, _S);
            _Ufill(_Q, _M, _X);
            _Ucopy(_P, _Last, _Q + _M);
            _Destroy(_First, _Last);
            allocator.deallocate(_First, _End - _First);
            _End = _S + _N;
            _Last = _S + size() + _M;
            _First = _S; }
        else if (_Last - _P < _M)
            {_Ucopy(_P, _Last, _P + _M);
            _Ufill(_Last, _M - (_Last - _P), _X);
            fill(_P, _Last, _X);
            _Last += _M; }
        else if (0 < _M)
            {_Ucopy(_Last - _M, _Last, _Last);
            copy_backward(_P, _Last - _M, _Last);
            fill(_P, _P + _M, _X);
            _Last += _M; }}




Wenn ich das richtig verstehe, dann wird zuerst überprüft, ob der allozierte Speicherbereich für den Container ausreicht, um die jeweilige Anzahl von Instanzen zu erstellen. Trifft das nicht zu, wird neuer Speicher reserviert und der komplette Vektor verlagert (erste IF-Klausel). Zum erstellen der neuen Instancen wird in diesem Fall wohl _Ufill() benutzt. Mit _Ucopy() wird danach der Rest des Vektors in den neuen Speicherbereich kopiert.

Auch im ersten ELSE-Bereich werden die neuen Instanzen wohl mit _Ufill erzeugt. Der dritte Bereich (ELSE IF) ist mir von der Bedeutung her noch nicht so ganz klar.

Ohne dass ich in _Ufill() nachgesehen hätte hört sich das natürlich sehr nach uninitialized_fill an.

Wenn jetzt der Konstruktor beim Einfügen in den Vektor gar nicht aufgerufen wird. Wann wird er denn dann aufgerufen? (vor der Benutzung der Instanz muss das ja wohl geschehen)

Das ist übrigens die in VC++ 6.0 enthaltene Implementierung der STL, ich wollte die Sache auch noch mal auf dem Amiga kompilieren mit der STL von www.stlport.org, kam aber leider noch nicht dazu.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: