2011-02-19 251 views
2

当我尝试添加QString到QMap作为QWidget类的析构函数中的关键字时,我目前坚持关于segfaults(有时是sigabrts由于不良的mallocs)我有 - 我认为它与QString的隐式共享有关模型和范围。复制到QMap时发生QString错误。范围问题?

我有一个QWidget充当MDI中的子窗口,这个QWidget有几个QGLWidget派生的视口实例作为子对象。在子窗口中有一个包含项目文件设置的QString,QVariant>包装类,当子窗口关闭时,它的析构函数调用QWidget :: deleteChildren(),它删除每个视口。在视口中析当前设置保存到子窗口的设置,如:

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

的sWin.setSetting()被调用每个我想保存的特性,“欧亚”是对一个参考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()行中的运算符+中得到一个sigabrt malloc():内存损坏。但是,在第二个视口的破坏开始时,不是第一个。

对于这个非常罗嗦的问题,我表示歉意,但是有大量的代码涉及遍布许多翻译单元。这个问题的任何线索将是一个很大的帮助!

在此先感谢。 凸轮


更新

我改变了我的第一个代码示例:

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

至于范围问题的测试。而它有时的作品,其他时间给出完全相同的错误;所以可能堆QString被破坏,这取决于它的内存位置是否被覆盖。但是这也是没有意义的,因为我没有调用delete,也没有关闭应用程序(只是一个MDI子窗口)!


更多的代码

斯文在堆上创建时被实例化一个新的子窗口。它被带入视类的析构函数从一个方法来自我的子窗口的引用:

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) 
+0

在哪里以及如何创建sWin以及何时以及如何删除(或被您删除)? – 2011-02-19 11:50:36

+0

Swin是在实例化新子窗口时创建的 - 在创建任何GUI组件之前。然后在子窗口析构函数的末尾删除它,我的子窗口类是从QWidget派生的,所以QWidget的析构函数在我的子窗口析构函数代码运行之前调用其子节点(我的视口对象)的delete。因此,sWin应始终处于范围之内,因为堆栈跟踪看起来正确,所以这一方似乎工作正常。 – cmannett85 2011-02-19 12:07:21

+0

您的子窗口类中的sWin成员是作为指针还是作为对象声明的?我认为如果你可以发布更多的代码,例如至少完整的析构函数和创建sWin的构造函数的部分,它会有所帮助。我有点困惑,因为你说sWin是一个参考。由于描述文件不能有参数,所以必须在描述文件中声明参考文件,这看起来很奇怪,并且可能会提示问题的原因。 – 2011-02-19 12:20:16

回答

0

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

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

0

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

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

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