传递弱指针没有多大意义,因为安全使用弱指针的唯一方法是将其转换回共享指针。 Qt 的 api 在这方面有些破损,因为它允许您使用 QWeakPointer::data() 作弊 - 但那很愚蠢,您永远不会那样使用它。 std::weak_ptr 做对了,除了将其转换为 std::shared_ptr 之外,您无法使用它。
但无论如何,这些都不是必需的。
Qt 的容器是隐式共享的值类。通过指针传递它们是多余的。 QVector 内部是指向其数据的共享指针。当您想放弃它的所有权时,您可以利用移动语义来消除原本会发生的隐式共享。
在您的特定情况下,答案是:根本不要使用外部共享指针。
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 容器的隐式共享是可以接受的,但这种风格在 Qt 5/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-4kbytes,则不要使用 std::list 或 QList,而是使用 std::vector 和 @ 987654349@,分别。一般来说,小列表在任何具有多级内存缓存的现代架构上表现极差。对于没有内存缓存的简单微控制器来说,它们可能没问题,所以我们在这里讨论的是 Arduino 性能水平,但即便如此,也必须先进行测量。