我正在寻找Qt智能指针的最佳实践。假设我有这样的东西。
void aFunction() {
QSharedPointer<QVector<QSharedPointer<Object> > > pointer = QSharedPointer<QVector<QSharedPointer<Object> > >(new QVector<QSharedPointer<Object> >);
doSomethingWithPointer(pointer);
changeOwnership(pointer);
}
然后在doSomethingWithPointer函数中
void doSomethingWithPointer(QSharedPointer<QVector<QSharedPointer<Object> > > pointer) {
pointer->append(QSharedPointer<Object>(new Object);
}
现在我在doSomethingWithPointer之后,传递指向changeOwnership的指针,它应该拥有它的所有权。我想知道的是doSomethingWithPointer。在这样的函数中传递共享指针可以吗?或者我应该使用QWeakPointer,因为doSomethingWithPointer实际上并没有获得指针的所有权。我应该在什么时候使用QWeakPointer?
发布于 2016-06-14 15:11:28
传递弱指针没有多大意义,因为安全使用弱指针的唯一方法是将其转换回共享指针。Qt的api在这方面有一定的缺陷,因为它允许您使用QWeakPointer::data()
进行欺骗--但这是愚蠢的,您不应该以这种方式使用它。std::weak_ptr
是正确的,除了将其转换为std::shared_ptr
之外,您不能使用它。
但这些都不是必要的。
Qt的容器是隐式共享值类。用指针来传递它们是多余的。内部的QVector
是指向其数据的共享指针。当您想要放弃它的所有权时,您可以利用move语义来去除否则会发生的隐式共享。
在您的特殊情况下,答案是:根本不要使用外部共享指针。
struct Object {};
void appendObject(QVector<QSharedPointer<Object>> & data) {
data.append(QSharedPointer<Object>(new Object));
}
void use(QVector<QSharedPointer<Object>> && data) {
}
int main() {
QVector<QSharedPointer<Object>> data;
appendObject(data);
use(std::move(data));
}
侧边栏:在C++11中,您可能希望uniform initialization能够工作--但是它不能工作,因为QVector
和/或QSharedPointer
有一个不兼容的API。所以这会很好,但不要骰子:
data.append({new Object});
用Qt 4风格编写它并依赖于Qt容器的隐式共享是可以接受的,但是这种风格在Qt5/C++11中是一个过早的悲观:
void use(QVector<QSharedPointer<Object>> & data) {
}
int main() {
QVector<QSharedPointer<Object>> data;
appendObject(data);
use(data);
}
还值得研究的是,Object
是否可以作为一个值类工作,该类可以通过值直接存储在容器中。
即使情况并非如此,如果您并不真正需要共享Object
的所有权,而只是一个动态分配的容器,则可以使用QList
:
struct Object {};
void appendObject(QList<Object> & data) {
data << Object();
}
void use(QList<Object> && data) {
}
int main() {
QList<Object> data;
appendObject(data);
use(std::move(data));
}
如果对象不可复制,则应使用std::list
并利用移动语义更改所有权:
void appendObject(std::list<QObject> & data) {
data.emplace_back();
}
void use(std::list<QObject> && data) {
}
int main() {
std::list<QObject> data;
appendObject(data);
use(std::move(data));
}
最后,如果您管理的类是从QObject
派生的,您可以利用QObject
作为一个QObject
容器:
void appendObject(QObject * container) {
new QObject(container); // add a child
}
void use(QScopedPointer<QObject> && container) {
for (auto object : container->children())
qDebug() << object;
}
int main() {
QScopedPointer<QObject> container;
appendObject(container.data());
use(std::move(container));
}
因为QObject
内部使用PIMPL、we can too,从而摆脱了愚蠢的外部指针。毕竟,QObject
是其pimpl的QScopedPointer
,就像大多数其他Qt类一样!
#include <QtCore>
#include <private/qobject_p.h>
class Container : public QObject {
public:
Container(QObject * parent = 0) : QObject(parent) {}
Container(Container && other) :
QObject(*new QObjectPrivate, other.parent()) {
d_ptr.swap(other.d_ptr);
}
};
void appendObject(Container & container) {
new QObject(&container); // add a child
}
void use(Container && container) {
for (auto object : container.children())
qDebug() << object;
}
int main() {
Container container;
appendObject(container);
appendObject(container);
use(std::move(container));
}
最后,如果您期望容器是“小”的,即元素的数目*元素的大小小于1-4K字节,那么不要使用std::list
或QList
,而是分别使用std::vector
和QVector
。一般来说,在任何具有多级内存缓存的现代体系结构中,小列表的性能都非常糟糕。对于没有内存缓存的简单微控制器来说,它们可能是可以的,所以我们在这里讨论的是Arduino的性能水平,但即使这样,也必须先进行测量。
https://stackoverflow.com/questions/37813706
复制相似问题