首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >函数参数中的Qt智能指针

函数参数中的Qt智能指针
EN

Stack Overflow用户
提问于 2016-06-14 13:37:53
回答 1查看 1.7K关注 0票数 0

我正在寻找Qt智能指针的最佳实践。假设我有这样的东西。

代码语言:javascript
运行
复制
void aFunction() {
    QSharedPointer<QVector<QSharedPointer<Object> > > pointer = QSharedPointer<QVector<QSharedPointer<Object> > >(new QVector<QSharedPointer<Object> >);

    doSomethingWithPointer(pointer);
    changeOwnership(pointer);
}

然后在doSomethingWithPointer函数中

代码语言:javascript
运行
复制
void doSomethingWithPointer(QSharedPointer<QVector<QSharedPointer<Object> > > pointer) {
    pointer->append(QSharedPointer<Object>(new Object);
}

现在我在doSomethingWithPointer之后,传递指向changeOwnership的指针,它应该拥有它的所有权。我想知道的是doSomethingWithPointer。在这样的函数中传递共享指针可以吗?或者我应该使用QWeakPointer,因为doSomethingWithPointer实际上并没有获得指针的所有权。我应该在什么时候使用QWeakPointer?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-14 15:11:28

传递弱指针没有多大意义,因为安全使用弱指针的唯一方法是将其转换回共享指针。Qt的api在这方面有一定的缺陷,因为它允许您使用QWeakPointer::data()进行欺骗--但这是愚蠢的,您不应该以这种方式使用它。std::weak_ptr是正确的,除了将其转换为std::shared_ptr之外,您不能使用它。

但这些都不是必要的。

Qt的容器是隐式共享值类。用指针来传递它们是多余的。内部的QVector是指向其数据的共享指针。当您想要放弃它的所有权时,您可以利用move语义来去除否则会发生的隐式共享。

在您的特殊情况下,答案是:根本不要使用外部共享指针。

代码语言:javascript
运行
复制
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。所以这会很好,但不要骰子:

代码语言:javascript
运行
复制
data.append({new Object});

用Qt 4风格编写它并依赖于Qt容器的隐式共享是可以接受的,但是这种风格在Qt5/C++11中是一个过早的悲观:

代码语言:javascript
运行
复制
void use(QVector<QSharedPointer<Object>> & data) {
}

int main() {
    QVector<QSharedPointer<Object>> data;
    appendObject(data);
    use(data);
}

还值得研究的是,Object是否可以作为一个值类工作,该类可以通过值直接存储在容器中。

即使情况并非如此,如果您并不真正需要共享Object的所有权,而只是一个动态分配的容器,则可以使用QList

代码语言:javascript
运行
复制
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并利用移动语义更改所有权:

代码语言:javascript
运行
复制
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容器:

代码语言:javascript
运行
复制
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类一样!

代码语言:javascript
运行
复制
#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::listQList,而是分别使用std::vectorQVector。一般来说,在任何具有多级内存缓存的现代体系结构中,小列表的性能都非常糟糕。对于没有内存缓存的简单微控制器来说,它们可能是可以的,所以我们在这里讨论的是Arduino的性能水平,但即使这样,也必须先进行测量。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37813706

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档