Verständnisfrage zum automatischen Reference Counting von Qt

Alles rund um die Programmierung mit Qt
Antworten
caetydid
Beiträge: 29
Registriert: 13. Januar 2006 22:25
Kontaktdaten:

Verständnisfrage zum automatischen Reference Counting von Qt

Beitrag von caetydid »

Hi,

soweit ich weiß, bieten alle QObject-Ableitungen ja die Möglichkeit des automatischen reference countings.
D.h. wenn ich ein QObject lösche, werden vorher dessen Kinder alle gelöscht.
Ich vermute mal, das "Hochzählen" geht über den "=" Operator...

Jetzt ist mir dazu folgendes passiert:

Ich habe Klasse A, die von B und C benutzt wird (in verschiedenen Threads, alle drei sind also auch QObjects).
Im Konstruktor von B und C übergebe ich ein A Objekt als "parent".

Code: Alles auswählen

MyApp::MyApp(...) : QApplication(...)
{
A a( this );
B b( &a );
C c( &a );
}
Wenn jetzt MyApp::~MyApp(){}
ausgeführt wird, sollten a, b, c doch sauber gelöscht werden, oder?

Weil ich in B und C auch const-Routinen von A benutzen will, habe ich
mir den Zeiger kopiert:

Code: Alles auswählen

B::B( A* parent ) : QThread( parent )
{
m_A = (const A* )parent;
...
}
Ist sowas überhaupt erlaubt, oder muß ich z.B.

Code: Alles auswählen

dynamic_cast<A*>(this->parent()) 
nutzen um an den Parent zu kommen?

Ich habe nämlich sonst das Problem, daß in Klasse B irgendwann nach dem Aufruf von A::~A() m_A ungültig wird und ich eine Methode damit aufrufe. Zu diesem Zeitpunkt darf b ja schon nicht mehr existieren!

Ich habe das Gefühl, daß Qt einem da sicher gute Hilfmittel mitgibt, ich sie aber nur noch nicht gefunden habe :)

vielen Dank für eure Hilfe!
caetydid >8^)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Verständnisfrage zum automatischen Reference Counting vo

Beitrag von Christian81 »

caetydid hat geschrieben: Wenn jetzt MyApp::~MyApp(){}
ausgeführt wird, sollten a, b, c doch sauber gelöscht werden, oder?
Ja, allerdings werden sie in deinem Fall schon nach verlassen des Konstruktors wieder gelöscht
caetydid hat geschrieben: Weil ich in B und C auch const-Routinen von A benutzen will, habe ich
mir den Zeiger kopiert:

Code: Alles auswählen

B::B( A* parent ) : QThread( parent )
{
m_A = (const A* )parent;
...
}
Ist sowas überhaupt erlaubt, oder muß ich z.B.

Code: Alles auswählen

dynamic_cast<A*>(this->parent()) 
nutzen um an den Parent zu kommen?
Beides überflüssig.... m_A = A; und fertig
caetydid hat geschrieben: Ich habe nämlich sonst das Problem, daß in Klasse B irgendwann nach dem Aufruf von A::~A() m_A ungültig wird und ich eine Methode damit aufrufe. Zu diesem Zeitpunkt darf b ja schon nicht mehr existieren!
Das verstehe ich gerade nicht was Du meinst... ausserdem gibt es QPointer
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
caetydid
Beiträge: 29
Registriert: 13. Januar 2006 22:25
Kontaktdaten:

Re: Verständnisfrage zum automatischen Reference Counting vo

Beitrag von caetydid »

Hi Christian, danke für die super-schnelle Antwort :)
Beides überflüssig.... m_A = A; und fertig
Hm klar. Kann er noch so casten...

caetydid hat geschrieben: Ich habe nämlich sonst das Problem, daß in Klasse B irgendwann nach dem Aufruf von A::~A() m_A ungültig wird und ich eine Methode damit aufrufe. Zu diesem Zeitpunkt darf b ja schon nicht mehr existieren!
Das verstehe ich gerade nicht was Du meinst... ausserdem gibt es QPointer
Okay, ich meinte folgendes:

Beim Beenden von MyApp erhalte ich eine Schutzverletzung, und zwar an einer Stelle in b, wo gerade eine Methode von a aufgerufen wird.
Der Zeiger auf a ( m_A ) ist an dieser Stelle bereits ungültig - das dürfte nicht sein.

Ich habe mir überlegt, ob ich eine Kopie des Zeigers des parent in b machen darf.
Wenn das den Zähler erhöht, dann wird a erst gelöscht, wenn b gelöscht wird (weil dann die m_A - Referenz gelöscht wird).
Aber eigentlich sollte das Löschen von a ja die Löschung seiner Kinder anstoßen.

caetydid >8^)
caetydid
Beiträge: 29
Registriert: 13. Januar 2006 22:25
Kontaktdaten:

Re: Verständnisfrage zum automatischen Reference Counting vo

Beitrag von caetydid »

Christian81 hat geschrieben:... ausserdem gibt es QPointer
Kann ich das eine oder andere mal gebrauchen.
Schlimm, muß meine Qt-Programme immer 20x umschreiben, weil ich immer wieder einen Weg finde, wie man irgendwas noch besser machen kann :)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Eine Pointer-Kopie erhöht nie irgend einen Counter! Ich würde mal ein bischen debuggen und Breakpoints bei den jeweiligen Destruktoren setzen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
caetydid
Beiträge: 29
Registriert: 13. Januar 2006 22:25
Kontaktdaten:

Beitrag von caetydid »

Christian81 hat geschrieben:Eine Pointer-Kopie erhöht nie irgend einen Counter! Ich würde mal ein bischen debuggen und Breakpoints bei den jeweiligen Destruktoren setzen.
Schon gemacht:
Zuerst wird A::~A aufgerufen, dann C::~C.
Und dann knallt's in B::run() (weil m_A ungültig ist).
B::~B wurde bis dahin nicht aufgerufen.

m_A muß doch so lange gültig bleiben, bis A::~A komplett abgearbeitet ist, oder?
Also sieht es für mich so aus, als ob B::~B einfach nicht aufgerufen wird, aber wie kann das sein, wenn das A-Objekt das 'parent' ist?

Sorry, vermutlich stehe ich irgendwie auf dem Schlauch...

caetydid >8^)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Übergibst Du auch den parent immer richtig an QObject?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
caetydid
Beiträge: 29
Registriert: 13. Januar 2006 22:25
Kontaktdaten:

Beitrag von caetydid »

Christian81 hat geschrieben:Übergibst Du auch den parent immer richtig an QObject?
An QThread (aber das erbt ja von QObject). Trotzdem könnte es was mit QThread zu tun haben, das QObject funktioniert nämlich.

Code: Alles auswählen

TrackerEngine::TrackerEngine( QObject* parent, unsigned int mtBufSize, unsigned int sdBufSize ) : 
	QObject( parent )
{
    mMotionTracker = new MotionTracker( this, mtBufSize );
    mCompass = new Compass( mMotionTracker );
    mStepDetector = new StepDetector( mMotionTracker, sdBufSize );
    ....
}

StepDetector::StepDetector( MotionTracker* mt, unsigned int bs ) : 
	mBufSize( qMin( bs, mt->bufferSize() - 1 ) ),
	QThread( mt )
{
    ...
    start();
}

Compass::Compass( MotionTracker* mt ) : QObject( mt )
{
    ...
}

Auf MotionTracker greife ich mit parent() zu.
In StepDetector::run() krachts dann...

Danke!
Caetydid >8^)
Antworten