我已经约了Qt单证阅读QPointer,QSharedPointer和QWeakPointer类.它说:
QPointer 是一个模板类,它提供了对Qt对象的保护指针,其行为类似于普通的C++指针,只是当被引用的对象被销毁并且没有产生"悬空指针"时它会自动设置为0.
QSharedPointer class拥有对共享指针的强引用.
QWeakPointer class持有对共享指针的弱引用.
我的问题是"这些课程有什么区别?".即指向对象的指针和指针的引用之间的区别是什么?它们都是指向具有不同机制和行为的对象的指针吗?
这两种指针有什么区别?据我所知,QSharedPointer可以很好地处理情况,那么QSharedDataPointer需要什么?
我有一种情况,QSharedPointer托管对象发出信号表明它已经完成了它的目的,并且很快就准备好删除了(执行后离开函数发出我的readyForDeletion信号).使用普通指针时,我只是调用QObject::deleteLater该对象,但是对于一个QSharedPointer管理实例来说这是不可能的.我的解决方法如下:
template<typename T>
class QSharedPointerContainer : public QObject
{
QSharedPointer<T> m_pSharedObj;
public:
QSharedPointerContainer(QSharedPointer<T> pSharedObj)
: m_pSharedObj(pSharedObj)
{} // ==> ctor
}; // ==> QSharedPointerContainer
template<typename T>
void deleteSharedPointerLater(QSharedPointer<T> pSharedObj)
{
(new QSharedPointerContainer<T>(pSharedObj))->deleteLater();
} // ==> deleteSharedPointerLater
Run Code Online (Sandbox Code Playgroud)
这很好用,但是使用这种方法有很多开销(分配一个新的QObject等等).有没有更好的解决方案来处理这种情况?
昨天我遇到了痛苦,让我感到沮丧24小时.问题归结为随机发生的意外崩溃.更复杂的是,调试报告也具有绝对随机的模式.更复杂的是,所有调试跟踪都会导致随机 Qt源或本机DLL,即证明每次问题都不在我身边.
这里有几个这样可爱的报告的例子:
Program received signal SIGSEGV, Segmentation fault.
0x0000000077864324 in ntdll!RtlAppendStringToString () from C:\Windows\system32\ntdll.dll
(gdb) bt
#0 0x0000000077864324 in ntdll!RtlAppendStringToString () from C:\Windows\system32\ntdll.dll
#1 0x000000002efc0230 in ?? ()
#2 0x0000000002070005 in ?? ()
#3 0x000000002efc0000 in ?? ()
#4 0x000000007787969f in ntdll!RtlIsValidHandle () from C:\Windows\system32\ntdll.dll
#5 0x0000000000000000 in ?? ()
Run Code Online (Sandbox Code Playgroud)
warning: HEAP: Free Heap block 307e5950 modified at 307e59c0 after it was freed
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000778bf0b2 in ntdll!ExpInterlockedPopEntrySListFault16 () from …Run Code Online (Sandbox Code Playgroud) 我的应用程序包含几个这样的函数:
void SomeClass::set_data_provider(DataProvider *data_provider)
{
connect(data_provider, SIGNAL(data_available(int)),
this, SLOT(data_available(int)));
}
Run Code Online (Sandbox Code Playgroud)
为了避免传递原始指针,我已将所有出现的更改DataProvider *为QSharedPointer<DataProvider>.后者几乎是前者的直接替代,除了你不能传递QSharedPointer QObject::connect.我通过从QSharedPointer中提取原始指针来解决这个问题:
void SomeClass::set_data_provider(QSharedPointer<DataProvider> data_provider)
{
connect(data_provider.data(), SIGNAL(data_available(int)),
this, SLOT(data_available(int)));
}
Run Code Online (Sandbox Code Playgroud)
这似乎工作正常,但它看起来不优雅,我担心像这样访问原始指针.有没有更好的方法连接到在QSharedPointer中传递的对象?
我有以下代码示例:
#include <QCoreApplication>
#include <QSharedPointer>
#include <QDebug>
#include <memory>
class A
{
public:
A()
{
throw 1;
}
~A() { qDebug() << "A destr"; }
};
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
try
{
//auto m1 = std::make_shared<A>();
auto m2 = QSharedPointer<A>::create();
}
catch (...)
{
qDebug() << "catch!";
}
return a.exec();
}
Run Code Online (Sandbox Code Playgroud)
上面代码的输出是:
A destr
catch!
Run Code Online (Sandbox Code Playgroud)
但如果我取消注释std::make_shared输出的行是如下:
catch!
Run Code Online (Sandbox Code Playgroud)
那么为什么要QSharedPointer::create调用不完整对象的析构函数呢?这是一个错误还是我错过了什么?
我用MSVC2013+ Qt 5.5.1和MSVC2015+ Qt 5.6(从源代码构建)尝试了它.结果是一样的.
由于历史原因,我QSharedPointer<T>在我的软件中使用.在某些时候,我们希望boost::shared_ptr<T>将该点存储到相同的数据中,并且应该保持该实例的存活QSharedPointer<T>.
执行此操作的常用方法是在删除器中保留另一个智能指针的副本boost::shared_ptr<T>.但是,为了防止缺失者由具有不同类型不同Ts,这将防止容易得到一个QSharedPointer背部boost::get_deleter,当corrresponding boost::shared_ptr一直上溯造型,我想原来的存储QSharedPointer<T>作为一个QSharedPointer<void>在删除器内,而不是使用T.
但我发现这QSharedPointer不能胜任任务,因为它在编译其标题时会抛出诸如"无法完成无效"的错误.
有没有人知道如何在不暴露T于删除器的情况下完成这项工作?
我需要一个指针容器来取得指针的所有权 - 即当一个元素被删除,或者容器超出范围时,它释放所有指针,就像在boost::ptr_vector.
QList<QScopedPointer<AbstractClass> > 不起作用(编译错误,没有复制构造函数?).
现在我正在使用QList<QSharedPointer<AbstractClass> >,但感觉就像一个矫枉过正,它的引用计数和多线程的昂贵的互斥量.
编辑:我刚刚了解了QPtrList(感谢@ForEveR),它在Qt3中非常相同,但是从更高版本中删除了.我只是不明白为什么他们会删除它.
在这个问题中,我能够适应这种QObject方法
QMetaObject::Connection
QObject::connect(const QObject * sender,
const char * signal,
const QObject * receiver,
const char * method,
Qt::ConnectionType type = Qt::AutoConnection)
Run Code Online (Sandbox Code Playgroud)
转换为接受a QSharedPointer而不是a QObject*作为其第一个参数的变体:
template<class T> QMetaObject::Connection
connect_from_pointer(const QSharedPointer<T> &sender,
const char *signal,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)
Run Code Online (Sandbox Code Playgroud)
我想对带有函数指针的版本做同样的事情,
QMetaObject::Connection
QObject::connect(const QObject * sender,
PointerToMemberFunction signal,
const QObject * receiver,
PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection)
Run Code Online (Sandbox Code Playgroud)
但我无法弄清楚PointerToMemberFunction它的定义是什么或在哪里定义!这是什么类型的?
我正在研究这个,但我没有看到一个确凿的答案.Qt小部件应用程序在退出时是否会清理内存?它是否与QObject有任何区别?如果有垃圾收集而不是为什么有QSharedPointer课?我是从我的代码的以下上下文中询问的.
void MainWindow::sync()
{
QString destPathUnixStyle = makePathUnix( _RootPath );
QString rsync_cmd = QString("rsync/rsync -a root@%1:/data/ '%2'").arg( _ip ).arg( destPathUnixStyle );
QProcess *syncProcess = new QProcess(this);
syncProcess->start( rsync_cmd );
qDebug() << "Sync started..";
connect(syncProcess, SIGNAL(finished(int)), this, SLOT(syncFinished()) );
_syncInProgress = true;
}
Run Code Online (Sandbox Code Playgroud)
现在syncProcess应用程序退出时我会被清理干净吗?如果用户在没有退出的情况下调用此函数一千次,会产生内存泄漏吗?
更新
鉴于上面的函数经常被调用很多次,是否更好地声明QProcess一个成员变量或者只是用于QSharedPointer改进上面的代码?
c++ ×10
qsharedpointer ×10
qt ×10
pointers ×2
qobject ×2
boost ×1
c++11 ×1
destructor ×1
memory-leaks ×1
pimpl-idiom ×1
qpointer ×1
qtcore ×1
shared-ptr ×1