Domanda

Al momento sono bloccato per quanto riguarda i segfault (a volte sigabrts a causa di malloc errati) ogni volta che provo ad aggiungere una QString a una QMap come chiave all'interno del distruttore della classe QWidget che ho - penso che abbia qualcosa a che fare con il modello di condivisione implicito di QString e scopo.

Ho un QWidget che funge da finestra secondaria in un MDI, questo QWidget ha alcune istanze di viewport derivate da QGLWidget come figli.Nella sottofinestra è presente una classe wrapper QMap< QString, QVariant > che contiene le impostazioni del file di progetto, quando la sottofinestra è chiusa, il suo distruttore chiama QWidget::deleteChildren() che elimina ciascuna delle finestre.Nel distruttore del viewport le impostazioni correnti vengono salvate nelle impostazioni della finestra secondaria, ad esempio:

QString dir = QString( "camera/" ) + name;
sWin.setSetting( dir + "/Projection",
                 static_cast< int >( camera_->getProjectionType() ) );

sWin.setSetting() viene chiamato per ciascuna delle proprietà che desidero salvare, 'sWin' è un riferimento alla classe wrapper QMap che viene eliminata alla fine del distruttore della sottofinestra.Tutto va bene fino alla chiamata setSetting(), che è semplicemente:

inline void setSetting( const QString& key, QVariant value )
{
    //  projectSettings_ is a standard QMap< QString, QVariant >.
    projectSettings_.insert( key, value );
}

Questa configurazione funziona bene per la prima vista, alla prima chiamata setSetting() della seconda, si verifica un segfault in:

inline QString::QString(const QString &other) : d(other.d)
{ Q_ASSERT(&other != this); d->ref.ref(); }

Vedo un errore di copia profonda quando il mio riferimento QString viene passato a QMap?Se sì, perché?La QString che ho creato non è ancora uscita dall'ambito poiché il distruttore non è tornato.E perché questo fallirebbe sulla seconda finestra e non sulla prima?

Di tanto in tanto ricevo un sigabrt malloc():corruzione della memoria in operator+ nella riga setSetting() del primo esempio di codice.Ma ancora una volta, all'inizio della distruzione del secondo punto di vista, non del primo.

Mi scuso per la domanda molto prolissa, ma è coinvolta una grande quantità di codice distribuito in molte unità di traduzione.Qualsiasi indizio su questo problema sarebbe di grande aiuto!

Grazie in anticipo.Camera


Aggiornamento

Ho cambiato il mio primo esempio di codice in:

QString* dir = new QString( "camera/" );
*dir += name;
sWin.setSetting( *dir + "/Projection",
                 static_cast< int >( camera_->getProjectionType() ) );

Come test per problemi di ambito.Ed esso A volte funziona e altre volte dà esattamente lo stesso errore;quindi presumibilmente l'heap QString viene distrutto, dipende solo dal fatto che la sua posizione di memoria sia stata sovrascritta o meno.Ma anche questo non ha senso, poiché non sto chiamando delete su di esso, né sto chiudendo l'applicazione (solo una sottofinestra MDI)!


Più codice

sWin viene creato nell'heap quando viene creata un'istanza di una nuova finestra secondaria.Viene portato nel distruttore della classe viewport come riferimento da un metodo dalla mia finestra secondaria:

inline Sy_project& getProject() { return *project_; }

Sy_project è (attualmente) una semplice classe wrapper per QMap.Il mio distruttore completo della classe base del viewport è questo (fallisce qui, non nella classe derivata):

Sy_abstractGLViewport::~Sy_abstractGLViewport()
{
    //  Write last viewport settings.
    QString name = objectName();
    Sy_project& sWin = projWindow_->getProject();
    QString dir = QString( "camera/" ) + name;

    //  Avoid "taking address of temporary" warning.
    QVector3D pos = camera_->getPosition();
    QVector3D foc = camera_->getFocalPoint();

    //  Save camera settings.  Dies on first setSetting() call.
    sWin.setSetting( dir + "/Projection",
                     static_cast< int >( camera_->getProjectionType() ) );
    sWin.setSetting( dir + "/position",
                     QVariant( 84, static_cast< void* >( &pos ) ) );
    sWin.setSetting( dir + "/focalPoint",
                     QVariant( 84, static_cast< void* >( &foc ) ) );
    sWin.setSetting( dir + "/FOV", camera_->getFOV() );
    sWin.setSetting( dir + "/nearClip", camera_->getPerspectiveClipRange()[0] );
    sWin.setSetting( dir + "/farClip", camera_->getPerspectiveClipRange()[1] );

    delete camera_;
}

Valgrind

Dopo aver utilizzato il memcheck di Valgrind ho scoperto numerose voci che sembravano simili al mio stacktrace.Non avendolo mai usato prima, sto ancora decifrando, ma questo sta dicendo che la mia classe Sy_project (wrapper per QMap) è stata cancellata Dopo la chiamata setSetting() lascia QMap con un riferimento non valido?

==12418== Invalid read of size 4
==12418==    at 0x805D872: QMap<QString, QVariant>::detach_helper() (qmap.h:730)
==12418==    by 0x805D380: QMap<QString, QVariant>::detach() (in /home/cbamber85/workspace/Syren GUI/Syren)
==12418==    by 0x805CDEE: QMap<QString, QVariant>::insert(QString const&, QVariant const&) (qmap.h:537)
==12418==    by 0x805CA33: Sy_project::setSetting(QString const&, QVariant) (Sy_project.h:50)
==12418==    by 0x805A78C: Sy_abstractGLViewport::~Sy_abstractGLViewport() (Sy_abstractGLViewport.cpp:67)
==12418==    by 0x808EDBC: Sy_QtGLViewport::~Sy_QtGLViewport() (Sy_QtGLViewport.cpp:91)
==12418==    by 0x808EE0E: Sy_QtGLViewport::~Sy_QtGLViewport() (Sy_QtGLViewport.cpp:100)
==12418==    by 0x4D66D63: QObjectPrivate::deleteChildren() (in /usr/lib/libQtCore.so.4.6.3)
==12418==    by 0x4306DDF: QWidget::~QWidget() (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x46FBE0E: QFrame::~QFrame() (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x475F173: QSplitter::~QSplitter() (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x475F1D1: QSplitter::~QSplitter() (in /usr/lib/libQtGui.so.4.6.3)
==12418==  Address 0xacf5b9c is 4 bytes inside a block of size 8 free'd
==12418==    at 0x40266AD: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==12418==    by 0x808D60F: Sy_project::~Sy_project() (Sy_project.h:30)
==12418==    by 0x808C9C6: Sy_subWindow::~Sy_subWindow() (Sy_subWindow.cpp:55)
==12418==    by 0x808CA84: Sy_subWindow::~Sy_subWindow() (Sy_subWindow.cpp:57)
==12418==    by 0x4D66482: qDeleteInEventHandler(QObject*) (in /usr/lib/libQtCore.so.4.6.3)
==12418==    by 0x4D67967: QObject::event(QEvent*) (in /usr/lib/libQtCore.so.4.6.3)
==12418==    by 0x4302ACB: QWidget::event(QEvent*) (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x42A9C63: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x42B1CA3: QApplication::notify(QObject*, QEvent*) (in /usr/lib/libQtGui.so.4.6.3)
==12418==    by 0x806010F: Sy_application::notify(QObject*, QEvent*) (Sy_application.cpp:14)
==12418==    by 0x4D54E0D: QCoreApplication::notifyInternal(QObject*, QEvent*) (in /usr/lib/libQtCore.so.4.6.3)
==12418==    by 0x4D589B3: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/lib/libQtCore.so.4.6.3)
È stato utile?

Soluzione

Penso che l'oggetto Sy_project a cui puntano il puntatore e quindi i riferimenti sia già distrutto nel momento in cui viene chiamato il distruttore di Sy_abstractGLViewport.Se guardi l'elenco di valgrind, il distruttore di Sy_project viene chiamato prima del distruttore di Sy_abstractGLViewport.

Quindi quando chiami inline Sy_project& getProject() { return *project_; } all'interno del distruttore Sy_abstractGLViewport, stai dereferenziando un puntatore penzolante.

Altri suggerimenti

Ronzio...Cosa succede se modifichi il codice per qualcosa del genere:

dir.append("/Projection");
sWin.setSetting(dir, static_cast<int>(camera_->getProjectionType()));

Nel modo in cui lo stai facendo, viene creata una copia temporanea e quindi associata a un riferimento a const, che dovrebbe essere ok.Successivamente da questo riferimento QMap tenterà di copiare l'argomento, in questo caso, passando attraverso il meccanismo di condivisione implicita di QString.Mi chiedo solo cosa potrebbe andare storto lì dentro...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top