[英]QString errors when copying into QMap. Scope issue?
每当我尝试将QString添加到QMap作为我拥有的QWidget类的析构函数内的键的时候,我目前都对segfaults(有时由于错误的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()行中得到一个sigabrt malloc(): operator +中的内存损坏 。 但是同样,在第二个视口开始销毁时,不是第一个。
对于这个非常冗长的问题,我深表歉意,但是涉及到大量的代码分布在许多翻译单元中。 任何有关此问题的线索将对您有很大帮助!
提前致谢。 凸轮
更新资料
我将第一个代码示例更改为:
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的memcheck之后,我发现了许多看起来与我的stacktrace类似的条目。 以前从未使用过它,但我仍在解密,这是否是说我的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)
哼!如果您将代码更改为以下内容,会发生什么:
dir.append("/Projection");
sWin.setSetting(dir, static_cast<int>(camera_->getProjectionType()));
用这种方式创建临时副本,然后将其绑定到对const的引用,应该可以。 此后,在这种情况下,QMap将尝试通过QString的隐式共享机制来复制参数。 我只是想知道那里可能出什么问题...
我认为您的指针和因此引用所指向的Sy_project对象在调用Sy_abstractGLViewport的析构函数时已经被销毁。 如果查看valgrind列表,则会在Sy_abstractGLViewport的析构函数之前调用Sy_project的析构函数。
因此,当您调用inline Sy_project& getProject() { return *project_; }
inline Sy_project& getProject() { return *project_; }
在Sy_abstractGLViewport析构函数中,你解引用野指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.