【问题标题】:Should I implement all my data classes as QSharedData and use it with QSharedDataPointer?我应该将所有数据类实现为 QSharedData 并将其与 QSharedDataPointer 一起使用吗?
【发布时间】:2012-07-14 19:46:11
【问题描述】:

我是 Qt 初学者,需要编写一些数据类。像QSharedDataPointer 示例 (here) 那样编写所有这些类是否是一种好方法,或者这是否会带来太多开销(除了工作量更大之外)?

我的课在性质上很像下面的Employee 课。我将不得不处理数百个实例,而不是一万或数百万。

我使用 QSharedData / QShareDataPointer 的动机是简化手动内存管理并具有通用代码样式。但我仍然不确定我是否监督了一些警告。

来自example

class EmployeeData : public QSharedData
 {
 public:
     EmployeeData();
     EmployeeData(const EmployeeData &other);
     ~EmployeeData();

     int id;
     QString *name;
 };

 class Employee
 {
 public:
     Employee();
     Employee(int id, const QString &name);

     void setId(int id) { d->id = id; }
     void setName(const QString &name);

     int id() const { return d->id; }
     QString name() const;

 private:
     QSharedDataPointer<EmployeeData> d;
 };

【问题讨论】:

    标签: c++ qt4 shared-data qshareddata


    【解决方案1】:

    使用 QSharedDataPointer/pImpl 的优点是:

    1) 在某些情况下,您可以避免一些数据复制(例如,如果您有两个或多个相同的 Employee 对象,它们可以共享相同的 EmployeeData 后端,而不是每个都有自己的相同数据的单独副本)

    2) 在向 EmployeeData 类添加额外的数据字段后,只需要重新编译 Employee 类的源代码,因为只有 Employee 类(可能)会直接访问 EmployeeData 类。您的所有其他代码将(可能)仅访问 Employee 类,因此不需要重新编译,因为 Employee 类的大小和布局不会改变。

    在适当的情况下,这两个原因都可能令人信服——例如,Qt 本身受益于 pImpl 和许多地方的隐式共享,因为 Qt 需要极其有效地处理大量数据,更重要的是因为 Qt 与第三方开发者要求它保证新的 Qt 共享库版本将保持向后兼容现有的第三方应用程序可执行代码,这些代码是针对旧 Qt 版本编译的。

    但是,对于您的个人计划,您不太可能会看到很多好处。如果您的数据对象与 EmployeeData 示例类中显示的一样小/简单(或者即使它们比这大 10 或 100 倍),那么仅制作数据副本的开销可能会很小......并且因为您大概可以在需要时重新编译自己的代码库,因此向后兼容的好处对您来说并不重要。

    所以我的建议是保持简单,按照标准的 C++ 方式做事,在必要时制作成员对象的常规旧默认复制构造函数样式副本(并尽可能通过 const-reference 将对象传递给方法,以尽量减少它们被复制的次数)。如果您注意到一个可衡量的性能问题,此时您可以返回并使用 pImpl/QSharedDataPointer 重写您的一些类,看看它是否为您提供了可衡量的加速(尽管您可能会发现它不会)。

    【讨论】:

    • 太好了,谢谢。但是有一个问题,除了工作量更大之外,使用 QSharedData 方法是否有任何明显的缺点。
    • 嗯,每次创建新的(非复制构造的)Employee 对象时,以及每次 QSharedDataPointer 类执行写时复制时,都需要额外的内存分配;当然,对 Employee 的每个方法调用都必须进行额外的取消引用才能获取 EmployeeData 中的实际数据。并不是说这些开销中的任何一个都可能在一个小程序中是可测量的。
    • 虽然额外的内存分配通常是一件坏事,但这个习惯用法偶尔会减少内存分配。我见过有五个或六个指向各种其他数据的指针的类,因此它们可以在头文件中前向声明,并且每个都在构造函数中单独分配。在这种情况下,更改为 pImpl 可以提高内存分配成本。
    • 同意 - 这取决于您可以利用多少共享。例如,Qt 中 QFont 的隐式共享是一个巨大的胜利,因为一个应用程序中几乎所有的成百上千个 QWidget 通常都使用相同的字体,而且字体数据是相当重量级的。
    猜你喜欢
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多