复制到QMap时出现QString错误。范围问题?

时间:2011-02-19 00:37:09

标签: c++ qt scope deep-copy qstring

当我尝试将QString添加到QMap作为我在QWidget类的析构函数中的键时,我目前仍然关注段错误(有时因为错误的mallocs而导致的sigabrts) - 我认为这与QString的隐式有关分享模式和范围。

我有一个QWidget充当MDI中的子窗口,这个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 );
}

此设置在第一个视口中正常工作,在第二个第一个setSetting()调用时,会发生一个段错误:

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

当我的QString引用传递给QMap时,我看到深层复制失败了吗?如果是这样,为什么?我创建的QString还没有超出范围,因为析构函数没有返回。为什么这会在第二个视口而不是第一个视口失败?

有时我会在第一个代码示例的setSetting()行的operator +中得到一个sigabrt malloc():内存损坏。但同样,在第二个视口的破坏开始时,不是第一个。

我为这个非常冗长的问题道歉,但是有很多代码涉及很多翻译单元。解决这个问题的任何线索都将是一个很大的帮助!

提前致谢。 凸轮


更新

我将我的第一个代码示例更改为:

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后,我发现了许多与我的堆栈跟踪类似的条目。从来没有使用它,我仍然在解密,但这是说我的Sy_project类(QMap的包装器)在 setSetting()调用之后被删除了,使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)

2 个答案:

答案 0 :(得分:0)

嗯......如果你改变这样的代码会发生什么:

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

在你做临时副本的方式是创建然后绑定到引用到const,这应该没问题。之后,从这个引用开始,QMap将尝试复制参数,在这种情况下,将通过QString的隐式共享机制。我只是想知道那里可能出现什么问题...

答案 1 :(得分:0)

我认为Sy_project对象是你的指针,因此指向的引用在调用Sy_abstractGLViewport的析构函数时已经被销毁了。如果查看valgrind列表,则会在Sy_abstractGLViewport的析构函数之前调用Sy_project的析构函数。

因此,当您在Sy_abstractGLViewport析构函数中调用inline Sy_project& getProject() { return *project_; }时,您将取消引用悬空指针。