2

私が持っているQWidgetクラスのデストラクタ内のキーとしてQMapにQStringを追加しようとすると、segfaults(mallocが悪いためにsigabrtsになることもあります)に関して現在立ち往生しています-QStringの暗黙の共有モデルと関係があると思います範囲。

MDIのサブウィンドウとして機能するQWidgetがあります。このQWidgetには、子としていくつかのQGLWidget派生ビューポートインスタンスがあります。サブウィンドウには、プロジェクトファイルの設定を含むQMap <QString、QVariant>ラッパークラスがあります。サブウィンドウを閉じると、デストラクタがQWidget :: deleteChildren()を呼び出して、各ビューポートを削除します。ビューポートデストラクタでは、現在の設定がサブウィンドウの設定に保存されます。例:

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

保存したいプロパティごとにsWin.setSetting()が呼び出されます。「sWin」は、サブウィンドウデストラクタの最後で削除されるQMapラッパークラスへの参照です。setSetting()を呼び出すまでは、すべて問題ありません。

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

この設定は最初のビューポートで正常に機能し、2番目の最初のsetSetting()呼び出しで、次の場所でセグメンテーション違反が発生します。

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

QString参照がQMapに渡されると、ディープコピーが失敗するのがわかりますか?もしそうなら、なぜですか?デストラクタが戻っていないため、作成したQStringはまだスコープから外れていません。そして、なぜこれは最初のビューポートではなく2番目のビューポートで失敗するのでしょうか。

ときどき、sigabrt malloc()が発生します。最初のコード例のsetSetting()行のoperator+でメモリが破損しています。しかし、繰り返しになりますが、最初のビューポートではなく、2番目のビューポートの破壊の開始時に。

非常に言葉の多い質問をお詫びしますが、多くの翻訳ユニットにまたがる大量のコードが関係しています。この問題の手がかりは大いに役立ちます!

前もって感謝します。カム


アップデート

最初のコードサンプルを次のように変更しました。

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

スコープの問題のテストとして。また、動作する場合もあれば、まったく同じエラーが発生する場合もあります。したがって、おそらくヒープQStringが破棄されているので、メモリ位置が上書きされているかどうかによって異なります。ただし、deleteを呼び出したり、アプリケーションを閉じたりしないため(MDIサブウィンドウのみ)、これも意味がありません。


その他のコード

sWinは、新しいサブウィンドウがインスタンス化されるときにヒープ上に作成されます。これは、サブウィンドウのメソッドからの参照としてビューポートクラスのデストラクタに取り込まれます。

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

Sy_projectは(現在)QMapの単純なラッパークラスです。私の完全なビューポート基本クラスデストラクタはこれです(派生クラスではなく、ここで失敗します):

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

Valgrindのmemcheckを使用した後、スタックトレースに似た多数のエントリを発見しました。これまで使用したことがないので、まだ解読中ですが、setSetting()呼び出しの後にSy_projectクラス(QMapのラッパー)が削除され、QMapに無効な参照が残っているということですか?

==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)
4

2 に答える 2

0

うーん...コードを次のように変更するとどうなりますか?

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

一時的なコピーを行う方法では、作成してからconstへの参照にバインドします。これで問題ありません。その後、この参照から、QMapは引数のコピーを試みます。この場合は、QStringの暗黙的な共有メカニズムを使用します。私はそこで何がうまくいかないのだろうかと思っています...

于 2011-02-19T16:01:29.460 に答える
0

ポインタ、つまり参照が指しているSy_projectオブジェクトは、Sy_abstractGLViewportのデストラクタが呼び出されるまでにすでに破棄されていると思います。valgrindリストを調べると、Sy_projectのデストラクタがSy_abstractGLViewportのデストラクタの前に呼び出されます。

したがってinline Sy_project& getProject() { return *project_; }、Sy_abstractGLViewportデストラクタ内で呼び出すと、ダングリングポインタを逆参照することになります。

于 2011-02-19T17:55:30.297 に答える