深入解析 Qt QMap 按值返回导致的重复构造

每次写

DeviceData deviceData = DataManager::dataManager()->getData(deviceId);

都会看到 DeviceData(int id) 被调用,主要是因为这原因:


getData 是按值(by‐value)返回,会新建一个临时对象

getData 定义是

const DeviceData getData(int id) const;

也就是说,它返回的是一个新的 DeviceData 对象,而不是对 deviceDatas 里已有对象的引用或指针

  • 如果 deviceDatas没有你要的 id,它会执行

    return DeviceData(id);
    

    这会调用 DeviceData(int) 构造函数来生成那个临时对象。

  • 如果 deviceDatas,它会走

    return deviceDatas.value(id);
    

    QMap::value() 本身也是按值返回,会调用拷贝构造函数(或者移动构造),从 deviceDatas[id] 拷贝/移动出一个新对象。虽然拷贝构造里没再调用 initData(),但你依然得生成一个新实例。

怎么改?

正确的做法:用 find()constFind() 拿到对已有元素的引用

不要在 const 环境下用 operator[],而应该这样写:

如果你希望直接拿到 deviceDatas 里已经初始化好的那个对象,不再新建,就把返回值改成引用指针

// 返回 const 引用
const DeviceData& DataManager::getData(int id) const {
    auto it = deviceDatas.find(id);
    if (it == deviceDatas.end()) {
        qDebug() << __func__ << "no such device:" << id;
        throw std::out_of_range("no such device");
    }
    return it.value();
}

或者

// 返回指针
const DeviceData* DataManager::getData(int id) const {
    auto it = deviceDatas.constFind(id);          // 不会插入,不会拷贝
    if (it == deviceDatas.constEnd()) {
        qDebug() << __func__ << "no such device:" << id;
        return nullptr;
    }
    return &it.value();                            // 取内部对象的地址
}

这样,你在调用时就不会再触发构造函数:

// 引用版本
const DeviceData& deviceData = DataManager::dataManager()->getData(deviceId);

// 指针版本
const DeviceData* pData = DataManager::dataManager()->getData(deviceId);
if (pData) {
    // ...
}

总结

  1. 按值返回 —— 每次都会新建一个 DeviceData,无论是用 DeviceData(id) 还是拷贝已有的,都要走构造/拷贝。

  2. deviceDatas 为空 —— 你一直走到“没找到就 new DeviceData(id)”的分支。

  3. 不要const 方法里用 deviceDatas[id] —— 那会调用 operator[] const,产生一个临时副本。

  4. find()constFind(),拿到一个迭代器,再用 it.value()(或者 (*it))来引用已有元素。这样既不插入新元素,也不做额外拷贝/构造。

  5. getData 改为返回引用或指针,避免不必要的构造/拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值