每次写
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) {
// ...
}
总结
-
按值返回 —— 每次都会新建一个
DeviceData
,无论是用DeviceData(id)
还是拷贝已有的,都要走构造/拷贝。 -
deviceDatas
为空 —— 你一直走到“没找到就 new DeviceData(id)”的分支。 -
不要在
const
方法里用deviceDatas[id]
—— 那会调用operator[] const
,产生一个临时副本。 -
要用
find()
或constFind()
,拿到一个迭代器,再用it.value()
(或者(*it)
)来引用已有元素。这样既不插入新元素,也不做额外拷贝/构造。 -
把
getData
改为返回引用或指针,避免不必要的构造/拷贝。