项目优化中对象的隐式共享

目录

一、项目优化背景       

二、继承QSharedData方式

2.1 继承QSharedData 定义数据

 2.2 QSharedDataPointer管理数据

2.3 测试使用

三、QSharedData原理

四、总结

          


一、项目优化背景
       

         在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; // 浅拷贝,共享同一个PersonData

	qDebug() << "p1:" << p1.name() << p1.age(); // 输出: Alice 25
	qDebug() << "p2:" << p2.name() << p2.age(); // 输出: Alice 25

	// 修改p2的数据,此时触发detach()
	p2.setAge(30);

	qDebug() << "p1 after p2 modification:" << p1.name() << p1.age(); // 输出: Alice 25
	qDebug() << "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引用返回值时直接返回对象(不要返回指针)注意线程安全限制 



    
  
    
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值