项目优化中对象的隐式共享
目录
一、项目优化背景
2.3 测试使用
四、总结
一、项目优化背景
在Qt框架中QString字符串 QByteArray字节数组 QImage图像类型 QList QVector Qmap等容器类 QVariant通用容器值 QPen QBrush等绘图相关类都是隐式共享的,即读时共享写时复制,极大的提高了对象的拷贝和存储效率,对于大对象的拷贝等很友好;但是项目中难免有一些自定义的大对象,如果能够享受这种隐式共享的福利也能提升软件的效率。
二、继承QSharedData方式
在Qt框架中可以很方便的让自定义数据继承QSharedData类,进而使用QSharedDataPointer管理数据即可使得数据拥有隐式共享的能力,以下是继承QSharedData的代码举例说明:
2.1 继承QSharedData 定义数据
#include <QSharedData>
class PersonData : public QSharedData {
public:QString name;int age;PersonData() : age(0) {}PersonData(const QString &n, int a) : name(n), age(a) {}
};
2.2 QSharedDataPointer管理数据
#include <QSharedDataPointer>
class Person {
private:// 使用隐式共享指针 引用计数管理生命周期 读时共享写时复制QSharedDataPointer<PersonData> d;public:Person() : d(new PersonData) {}Person(const QString &name, int age) : d(new PersonData(name, age)) {}// 拷贝构造函数是隐式的,浅拷贝Person(const Person &other) : d(other.d) {}// 赋值运算符也是浅拷贝Person &operator=(const Person &other) {d = other.d;return *this;}~Person() {}// 修改数据时自动触发深拷贝(写时复制)void setName(const QString &name) {d.detach(); // 如果当前有多个引用者,则复制一份新的数据并d指向该新数据d->name = name;}void setAge(int age) {d.detach(); // 如果当前有多个引用者,则复制一份新的数据d->age = age;}QString name() const { return d->name; }int age() const { return d->age; }
};
2.3 测试使用
void TestQSharedData()
{Person p1("Alice", 25);Person p2 = p1; // 浅拷贝,共享同一个PersonDataqDebug() << "p1:" << p1.name() << p1.age(); // 输出: Alice 25qDebug() << "p2:" << p2.name() << p2.age(); // 输出: Alice 25// 修改p2的数据,此时触发detach()p2.setAge(30);qDebug() << "p1 after p2 modification:" << p1.name() << p1.age(); // 输出: Alice 25qDebug() << "p2 after modification:" << p2.name() << p2.age(); // 输出: Alice 30
}
三、QSharedData原理
隐式共享指针基本原理和共享指针一样,都是基于引用计数判定是否进行实际对象的删除,类似于shared_ptr;只是在此基础上对于对象的修改做了优化,detach操作判定引用计数为大于1时会重新创建对象,即写时复制。
区别于std::shared_ptr若需要两个指针独立时必须进行深拷贝如下:
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = std::make_shared<int>(*p1); // 拷贝 p1 指向的值
SharedPointer只需要在修改前detach即可。
基于引用计数的隐式共享实现原理(简化):
基于引用计数的隐式共享实现原理(简化)
template <typename T>
class SharedPointer {
public:SharedPointer() : data(nullptr), refCount(new int(1)) {}SharedPointer(const SharedPointer& other): data(other.data), refCount(other.refCount) {++(*refCount);}SharedPointer& operator=(const SharedPointer& other) {if (this != &other) {if (--(*refCount) == 0) {delete data;delete refCount;}data = other.data;refCount = other.refCount;++(*refCount);}return *this;}~SharedPointer() {if (--(*refCount) == 0) {delete data;delete refCount;}}T* operator->() { return data; }//前面与共享指针类似 detach基于refcnt进行深拷贝void detach() {if (*refCount > 1) {T* newData = new T(*data);--(*refCount);data = newData;refCount = new int(1);}}
private:T* data;int* refCount;
};
四、总结
Qt的隐式共享和享元模式提供了以下优势:
内存效率:减少不必要的数据复制
性能优化:值传递变得轻量级
简洁API:无需手动管理引用计数
灵活性:结合const引用可进一步优化性能在实际开发中,应当:优先通过const引用传递隐式共享对象需要修改时使用非const引用返回值时直接返回对象(不要返回指针)注意线程安全限制