Files
VX5_KRO_GearPump/doc/DateItemModel改进与修改_再review.md
T

240 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DateItemModel 改进与修改 —— 再 Review
> 本文档对 `doc/DateItemModel改进分析.md` 与 `doc/DateItemModel修改总结.md` 描述的改造工作进行交叉核对,比对实际代码(`scene/ViewModels.h/.cpp`、`DateVarSet.cpp`、`scene/DateReplaceEditor.cpp`、`scene/BarcodeEditor.cpp`、`scene/ItemCommon.cpp/.h`),列出确实落地、漏改、以及隐藏风险的部分。
---
## 1. 总体评估
文档描述的整体改造方向(`QStringList → std::array<QString,N>`、移除 `createDefaultReplaceModel`、新增默认构造函数、`QMap<int,QString> yearsMap → std::array<QString,16> yearsArray + int startYear`)在以下文件里**基本落地**:
- `scene/ViewModels.h`:成员类型替换 ✅;声明默认构造函数 ✅;移除 `createDefaultReplaceModel` ✅。
- `scene/ViewModels.cpp`:默认构造函数初始化各数组 ✅;`loadFromXml` / `saveToXml` 改为新结构 ✅(**有缺陷,见 §2.2**)。
- `scene/DateReplaceEditor.cpp`:`dateModel()` / `setDateModel()` 改为循环复制 ✅。
- `scene/BarcodeEditor.cpp`:默认值兜底逻辑、模型搬运改为新结构 ✅。
- `scene/ItemCommon.cpp`:年份访问改为 `startYear + index` ✅。
但存在 **1 处编译错误** 与 **1 处数据丢失隐患**,外加若干小瑕疵。
---
## 2. 严重问题(必须修复)
### 2.1 🔴 `DateVarSet.cpp:540` 编译失败 —— 修改总结里漏改的关键一行
```cpp
// DateVarSet.cpp 当前代码
yearList = model.yearsArray; // ❌ QStringList 不能直接 = std::array<QString,16>
```
`yearList` 是 `DateVarSet.h` 中声明的 `QStringList`;`model.yearsArray` 是 `std::array<QString, 16>`。两者之间**没有赋值运算符**,这一行直接编译错误。
`scene/DateReplaceEditor.cpp` 的对应位置已经改成了循环写入,但 `DateVarSet.cpp` 对此漏掉。
**修复**(与同文件 510~534 行其它 list 保持一致):
```cpp
yearList.clear();
for (size_t i = 0; i < model.yearsArray.size(); ++i) {
yearList.append(model.yearsArray[i]);
}
```
> 影响面:编译过不去,整个 Qt 工程构建失败。
---
### 2.2 🔴 `loadFromXml` 没还原 `startYear` —— 跨年加载会丢用户配置
`scene/ViewModels.cpp::loadFromXml` 的相关片段:
```cpp
m.startYear = QDate::currentDate().year(); // ← 永远用当前年份当 startYear
auto yearsMap = attrs.value("yearsMap").toString().split("<br>");
for (auto it = yearsMap.begin(); it != yearsMap.end(); ++it) {
auto yearPair = it->split("<subbr>");
int year = yearPair[0].toInt();
if (year >= m.startYear && year < m.startYear + 16) { // ← 早于当前年的全部丢弃
int index = year - m.startYear;
m.yearsArray[index] = yearPair[1];
}
}
```
而 `saveToXml` 是按 `m.startYear + i` 写出去的:
```cpp
for (int i = 0; i < 16; ++i) {
int year = m.startYear + i;
yearsMap.append(QString("%1<subbr>%2<br>").arg(year).arg(m.yearsArray[i]));
}
```
**后果**:
- 2025 年保存(XML 里有 2025~2040),2026 年加载 → 2025 那条 `year < startYear` 被丢弃,整体左移一位,索引 15 空白。
- 2024 年保存,2026 年加载 → 2024、2025 两条全丢,错位 2 位。
- 用户**任何针对早于"系统当前年"的自定义年份映射,下次加载都会消失**。
**修复(推荐)**:把 `startYear` 作为独立 XML 属性持久化:
```cpp
// saveToXml
attrs.append("startYear", QString::number(m.startYear));
// loadFromXml
int sy = attrs.value("startYear").toInt();
m.startYear = (sy != 0) ? sy : QDate::currentDate().year(); // 兼容旧文件
```
或退而求其次,loadFromXml 用 XML 里第一条 year 设定 `m.startYear`。
> 影响面:用户在编辑器里配置的年份字串,跨年使用会静默丢失/错位。
---
## 3. 次要问题(不影响编译,建议修)
### 3.1 🟡 `scene/ItemCommon.h` 头注释未同步
```
* - yyyy: 四位数年份,支持替换为自定义字符串(通过 model.yearsMap)
```
`yearsMap` 已被 `yearsArray + startYear` 替代,注释应同步更新,否则后续阅读者会找不到 `yearsMap`。
---
### 3.2 🟡 `dateModel()` 写入年份时丢了"用户起始年"语义
`DateVarSet.cpp::dateModel()` 与 `scene/DateReplaceEditor.cpp::dateModel()` 都是这种写法:
```cpp
DateItemModel model; // model.startYear = 当前年(来自默认构造函数)
for (int i = 0; i < yearInitList.size() && i < 16; ++i) {
int year = yearInitList[i];
if (year >= model.startYear && year < model.startYear + 16) {
int index = year - model.startYear;
model.yearsArray[index] = yearList[i];
}
}
```
由于当前 `yearInitList` 也是从今年开始填充的,**当前能凑巧跑通**;但这里没有把 UI 里实际看到的起始年同步回 `model.startYear`。一旦未来扩展为"展示历史年份"或"展示从某指定年开始的年份序列",这里会静默丢数据。
**更直白的写法**:
```cpp
if (!yearInitList.isEmpty()) {
model.startYear = yearInitList.first();
}
const int n = std::min(yearInitList.size(), 16);
for (int i = 0; i < n; ++i) {
model.yearsArray[i] = yearList[i];
}
```
---
### 3.3 🟡 signed/unsigned 比较警告
`DateVarSet.cpp` / `scene/DateReplaceEditor.cpp` 中大量这样写:
```cpp
for (size_t i = 0; i < std::min(dataList.size(), static_cast<int>(model.dataMap.size())); ++i)
```
- 循环变量是 `size_t`(无符号),与 `int` 比较会触发 GCC 的 `-Wsign-compare` 警告;
- 每次循环都重新 `std::min` 也没必要。
**建议**改为:
```cpp
const int n = std::min<int>(dataList.size(), static_cast<int>(model.dataMap.size()));
for (int i = 0; i < n; ++i) { ... }
```
---
### 3.4 🟡 `scene/BarcodeEditor.cpp` 五个手写循环冗余
```cpp
for (size_t i = 0; i < m_vm.dateViewModel.dataMap.size(); ++i) {
m_vm.dateViewModel.dataMap[i] = rep.dataMap[i];
}
// ... 类似 5 段 ...
m_vm.dateViewModel.yearsArray = rep.yearsArray; // 这里直接赋值是对的
```
`std::array` 自身就支持 `=`,最后一行 `yearsArray` 已经这样写了。前面 5 段 `for` 循环都可以直接简化:
```cpp
m_vm.dateViewModel.dataMap = rep.dataMap;
m_vm.dateViewModel.daysMap = rep.daysMap;
m_vm.dateViewModel.monthsMap = rep.monthsMap;
m_vm.dateViewModel.weeksMap = rep.weeksMap;
m_vm.dateViewModel.hoursMap = rep.hoursMap;
```
不影响功能,纯属冗余。
---
## 4. 文档与实现不一致清单
| 文档原话 | 实际代码 | 影响 |
|---|---|---|
| "DateVarSet.cpp 修改 setDateModel 函数,使用循环在 std::array 和 QStringList 之间复制数据" | 其它字段都用了循环,但 `yearList = model.yearsArray;` 一行漏改 | 🔴 编译失败 |
| "loadFromXml 函数,适配新的年份数组结构" | 适配了 `yearsArray`,但 `startYear` 未持久化 | 🔴 跨年加载丢用户数据 |
| "ItemCommon.cpp 更新了年份映射访问逻辑,适配新的 yearsArray 和 startYear 结构" | `.cpp` 已改,但 `.h` 头注释仍引用 `yearsMap` | 🟡 文档失同步 |
| "保持了兼容性:接口不变,仅内部实现改变" | XML schema 已变(`yearsMap` 编码方式变化、缺少 `startYear` 字段) | 🔴 与已部署设备的存档不完全互通 |
---
## 5. 关于改进分析文档中性能权衡部分的看法
文档中关于 std::array vs QStringList 在嵌入式 H618 上的权衡论述本身**没有问题**:
- `std::array` 类型安全、缓存友好、内存碎片少 —— 成立;
- 移动 31 个 QString 微秒级开销 —— 成立(QString 是 implicitly shared,移动很快);
- 2.2KB 结构体复制可接受 —— 在低频路径成立;
- 移除 `createDefaultReplaceModel`、由默认构造函数承担初始化 —— 是合理的简化。
但有两点提醒:
1. **`std::array<QString,N>` 移动 ≠ "transfer pointer" 的 O(1)**。每个 QString 元素逐个移动,引用计数不变但仍要逐个调用移动构造,总体 O(N)。N=31 时不是性能问题,但与文档"只需转移指针和引用计数"那一段的描述不太一致。
2. **2.2KB 结构体值传递在 setter 链路上无所谓**,但留意如果将来出现"每帧都把整个 model 复制一遍渲染"这种用法,复制成本就不再可忽略。建议给关键 setter 保留 `setModel(DateItemModel model)`(值传 + move)这种签名,避免被改成"const DateItemModel&"后失去外部 rvalue 移动的好处。
---
## 6. 结论
- **建议至少修掉 §2.1 与 §2.2**:前者不修无法编译;后者不修跨年加载会丢用户在编辑器里配置的年份字串,且无任何运行时报错(最危险的那种 bug)。
- §3 的几条都是清理性工作,可按需进行。
- §4 中关于"接口不变 = 完全兼容"的说法在 XML schema 层面其实已不成立,老存档与新固件的双向兼容性需要单独评估。
---
## 7. 修复 Patch 摘要(建议改动)
```diff
// DateVarSet.cpp (around line 540)
- yearList = model.yearsArray;
+ yearList.clear();
+ for (size_t i = 0; i < model.yearsArray.size(); ++i) {
+ yearList.append(model.yearsArray[i]);
+ }
// scene/ViewModels.cpp saveToXml
+ attrs.append("startYear", QString::number(m.startYear));
// scene/ViewModels.cpp loadFromXml
- m.startYear = QDate::currentDate().year();
+ {
+ int sy = attrs.value("startYear").toInt();
+ m.startYear = (sy != 0) ? sy : QDate::currentDate().year();
+ }
// scene/ItemCommon.h 注释更新
- * - yyyy: 四位数年份,支持替换为自定义字符串(通过 model.yearsMap)
+ * - yyyy: 四位数年份,支持替换为自定义字符串(通过 model.yearsArray + model.startYear)