diff --git a/AecDbEwEquipment-analysis.md b/AecDbEwEquipment-analysis.md index 5015856..806e372 100644 --- a/AecDbEwEquipment-analysis.md +++ b/AecDbEwEquipment-analysis.md @@ -302,7 +302,7 @@ void dwgOutFieldsForXPrim(AecEqui::XPrimData *pSolid, ...) // :239 顺带处理:跳过 `NULL` 指针并单独计数,避免"写了数量但循环少写一条"导致读写错位;删掉原来定义后未使用的 `int num`。 -### 3.2 P1:`subErase` 里 `Find` 当布尔用 +### 3.2 P1:`subErase` 里 `Find` 当布尔用(已修复) ```cpp if (eSubType == eValve || sName.Find(_T("阀")) != -1 || sName.Find(_T("接头"))) // :2119 @@ -310,7 +310,9 @@ if (eSubType == eValve || sName.Find(_T("阀")) != -1 || sName.Find(_T("接头") `CString::Find` 找不到返回 `-1`,非 0 即真,所以**第三个条件恒真**。整句等价于"永远是阀门",删除任何设备都会走合并管线那段逻辑(`GetInterface` + `PushGripMessage`)。应写成 `!= -1`。 -### 3.3 P1:`DrawHandFlg` 用 `==` 赋值 +**已修复**:补 `!= -1`。删除普通设备不再误走阀门/接头的合并管线分支。 + +### 3.3 P1:`DrawHandFlg` 用 `==` 赋值(已修复) ```cpp if (nVt == 1) sFlag = _T("M"); @@ -320,7 +322,9 @@ else sFlag == _T("Y"); // :2656 应为 = 液动(3)时文字为空,画出来是空标注。另外这里直接取 `GetInterface(0)` / `GetInterface(1)`,接口不足 2 个时 `inf2` 是默认值,`distanceTo` 为 0、`normalize()` 得到零向量,后续 `angleTo` 结果不可信。 -### 3.4 P1:`ProcessHlrResult` 在遍历中删 map 元素 +**已修复**:`==` 改为 `=`,液动阀(3)现在会画出 `Y`。接口不足 2 个时 `inf2` 取默认值、方向不可信的问题未动,属于显示容错,另行评估。 + +### 3.4 P1:`ProcessHlrResult` 在遍历中删 map 元素(已修复) ```cpp for (; it != _preAr.end(); ++it) @@ -332,7 +336,9 @@ for (; it != _preAr.end(); ++it) 应改为 `it = _preAr.erase(it);`。这是典型的偶发崩溃点(容器元素少时不容易复现)。 -### 3.5 P1:`GetSectionDraw` 返回值取反 +**已修复**:改成 `while` + `erase(it++)`。没有用 `it = erase(it)`,因为 R190 走的是 C++98 标准(`cmakelists.txt` 按 SDK 版本切换),C++03 的 `map::erase(iterator)` 返回 `void`。 + +### 3.5 P1:`GetSectionDraw` 返回值取反(已修复) ```cpp int nCount = arRegionPtrs.length(); @@ -343,6 +349,10 @@ return (nCount - nCoundPre); // :12762 顺序反了 返回的是"调用前 − 调用后",恒为 0 或负数。若调用方用它判断"是否剖到东西",判断必然失败。 +**已修复**:改为 `nCoundPre - nCount`。全库调用点都忽略这个返回值,所以此前没有实际故障。 + +注意:`AecDbEwFitting.cpp:16523`、`AecDbECFitting.cpp:8751` 的同名函数是一模一样的写法(同样的错误),本次未改,见 5.4。 + ### 3.6 P1:`HLR_CALC` 标志会被存进图纸 `Draw3d:3009` 一旦读到 `HLR_CALC` 为真就直接返回,什么都不画。这个标志由 `PreprocessForHlr:13204` / `:13360` 置真、`ProcessHlrResult:13107` 复位。 @@ -360,11 +370,13 @@ return (nCount - nCoundPre); // :12762 顺序反了 米制图纸里,同一份数据经两个入口读出来的接口尺寸差 1000 倍。`Draw*Vlv2d` 用下标版,`subErase` / `PreprocessForHlr` 用数组版,两边算出来的东西对不上。 -### 3.8 P1:`copyFrom` 漏拷字段 +### 3.8 P1:`copyFrom` 漏拷字段(已修复) `:2174` 只拷了 `m_mapSpecXData` / `m_nInfActive` / `m_ptInsert` / `m_vtDir` / 几何单元,**没有拷 `m_bVert`、`m_idDash`、`m_idCenter`**。复制粘贴一个竖放阀门,粘贴出来是横放的;两个图层软指针也丢了(虚线和中心线会跑到默认图层)。 -### 3.9 P2:`MakeBlockRefSet` 的范围累加逻辑错 +**已修复**:补拷 `m_bVert` / `m_idDash` / `m_idCenter`。 + +### 3.9 P2:`MakeBlockRefSet` 的范围累加逻辑错(已修复) ```cpp for (...) { @@ -382,7 +394,9 @@ for (...) { 应改成 `if (isValidExtents(extAdd)) ext.addExt(extAdd);`,块参照分支直接 `continue`。 -### 3.10 P2:`byJson` 的 `m_pData` 尺寸对不上 +**已修复**:块参照直接 `continue`;`extAdd` 每轮重新构造并检查 `getGeomExtents` 返回值;判断对象改为 `extAdd`。 + +### 3.10 P2:`byJson` 的 `m_pData` 尺寸对不上(已修复) ```cpp p->m_nSize = it->value.GetInt(); // 字节数(来自 __nSize__) @@ -393,16 +407,20 @@ p->m_pData = new PVOID[br._len]; // 按 PVOID 个数分配 分配长度取决于 `br._len`,使用长度取决于 `m_nSize`,两者来自不同字段。JSON 被改过或版本不一致时就会越界读写。应按 `m_nSize` 分配并校验 `sizeof(PVOID)*br._len >= m_nSize`。 -### 3.11 P2:开图读入没有边界校验 +**已修复**:`br._len` 本来就是字节数,改为 `new byte[br._len]` + `memcpy(..., br._len)`,并用 `br._len` 覆盖 `m_nSize`(两者不一致时以实际数据长度为准)。 + +### 3.11 P2:开图读入没有边界校验(已修复) `dwgInFieldsForXPrim:172`: -- `readInt32(&nSize)` 后直接 `new byte[pSolid->m_nSize]`(`:193`),负值或超大值都没有检查(负值转 `size_t` 会申请巨大内存) +- `readInt32(&nSize)` 后直接 `new byte[pSolid->m_nSize]`(`:193`),超大值没有检查(负值被 `> 0` 挡住,不会分配) - `readBytes` 的返回值没有检查 - `m_Combins` 是**递归**读(`:227`),没有深度上限,损坏的图纸可以打爆栈 同类的 `AcDbX3dSolid` 阶段一、二已经补过类似的防护,这里可以照搬。 +**已修复**:加 16MB 上限(`kMaxXPrimDataSize`),超限 `setFilerStatus(Acad::eInvalidInput)` 让整个 `dwgInFields` 退出;`readBytes` 检查返回值,失败时释放并清零。`m_Combins` 的递归深度上限未加,损坏图纸仍可能打爆栈,优先级低。 + ### 3.12 P2:`PreprocessForHlr` 的"对面"被变换了两次 ```cpp @@ -417,14 +435,18 @@ for (...) { 原实体在 `-H/2` 位置,克隆体被移到 `+H` 位置(两次 `+H/2`),两侧不对称。除非这是刻意做的"厚度补偿",否则应只乘一次。建议拿一个剖切样例对照确认。 -### 3.13 P2:`GetBodyBox` 恒返回 `TRUE` +### 3.13 P2:`GetBodyBox` 恒返回 `TRUE`(已修复) `:4205` 无论有没有取到实体都 `return TRUE`;且 `ar3D` 引用在 `Draw3d` 之前就绑定了(`:4207`)。当前 `Get3DBuffer()` 返回成员引用,重新填充不会换对象,所以能工作;但如果哪天改成返回副本就会静默失效。返回值也应反映实际结果。 -### 3.14 P2:`clearGeoBuffer()` 是空实现 +**已修复**:返回实际是否取到范围;`_ext` 改为每轮新建,避免把上一轮的累积结果重复并入。11 处调用点都忽略返回值,行为不变。 + +### 3.14 P2:`clearGeoBuffer()` 是空实现(已修复) `:12861` 函数体只有 `AssertWriteEnabled();`。`PipelineCmd/EquipmentMakeDlg.cpp` 有 8 处调用,本意应该是清掉 2D/3D 缓存(`Clean2DBuffer` / `Clean3DBuffer`)。现在是"调了没反应",改了参数后旧几何还在。 +**已修复**:改为 `Clean2DBuffer(); Clean3DBuffer();`。调用方(`EquipmentMakeDlg`、`EQU_MODIFY`、`ParamEquJson`)都是改完参数后调它,语义一致。 + ### 3.15 P2:`booleanOper` 的所有权写法在本文件里自相矛盾 同一文件里两种写法并存: @@ -539,21 +561,25 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 ### 5.1 第一批:内存与正确性(不改接口、不改格式) -拆成两批提交:**内存问题已做(见 2.13)**,逻辑缺陷待做。 +分两批提交:**内存问题已完成(见 2.13)**,**逻辑缺陷已完成(见 3.2~3.14)**。 -| # | 改动 | 位置 | 风险 | 状态 | -| --- | --- | --- | --- | --- | -| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | `:1707` `:1720` | 低 | 已完成 | -| 2 | 析构补 `FreeSubPrimData()` | `:1686` | 低(依赖 #3) | 已完成 | -| 3 | `releaseData()` 统一 `delete[]`,`FreeSubPrimData()` 释放 `m_pData` 后删结构体 | `:1520` | 低 | 已完成(见 2.3、2.13) | -| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | `:3159` | 中(涉及几何正确性,需样例图) | 已完成 | -| 5 | `RemoveSubPrimObj*` 补释放 `m_pData` | `:4276` `:4291` | 低 | 已完成 | -| 6 | `subErase` 的 `Find` 补 `!= -1` | `:2119` | 低(行为会变,需回归删除阀门) | 待做 | -| 7 | `DrawHandFlg` 的 `==` 改 `=` | `:2656` | 低 | 待做 | -| 8 | `ProcessHlrResult` 改用 `it = erase(it)` | `:13128` | 低 | 待做 | -| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | `:2174` | 低 | 待做 | -| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | `:12762` | 低(需确认调用方语义) | 待做 | -| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | `:12861` | 低 | 待做 | +| # | 改动 | 风险 | 状态 | +| --- | --- | --- | --- | +| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | 低 | 已完成 | +| 2 | 析构补 `FreeSubPrimData()` | 低 | 已完成 | +| 3 | `releaseData()` 统一 `delete[]`,`FreeSubPrimData()` 释放 `m_pData` 后删结构体 | 低 | 已完成(见 2.3、2.13) | +| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | 中 | 已完成 | +| 5 | `RemoveSubPrimObj*` 补释放 `m_pData` | 低 | 已完成 | +| 6 | `subErase` 的 `Find` 补 `!= -1` | 低(行为会变) | 已完成 | +| 7 | `DrawHandFlg` 的 `==` 改 `=` | 低 | 已完成 | +| 8 | `ProcessHlrResult` 改用 `while` + `erase(it++)` | 低 | 已完成 | +| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | 低 | 已完成 | +| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | 低 | 已完成 | +| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | 中(影响所有改参数路径) | 已完成 | +| 12 | `MakeBlockRefSet` 范围累加改判 `extAdd` | 低 | 已完成 | +| 13 | `byJson` 按字节长度分配 `m_pData` | 低 | 已完成 | +| 14 | `dwgInFieldsForXPrim` 加尺寸上限与读失败处理 | 低 | 已完成 | +| 15 | `GetBodyBox` 返回实际结果 | 低 | 已完成 | 另外补做的 4 处内存修复(2.6、2.7、2.9、2.10、2.11、`GetDraw3dables` 合并泄漏、`dwgInFields` 的 `RemoveAll`)见 2.13。 @@ -581,9 +607,12 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 ### 5.4 需要先确认的事 1. ~~`booleanOper` 是否删除入参(3.15)~~ —— 2026-10-23 按「不删除入参」处理,理由见 3.15 -2. `GetSectionDraw` 的返回值调用方到底期望什么(3.5) -3. `PreprocessForHlr` 的 `mat4` 双次变换是否刻意(3.12) -4. ~~`kCombination` 单元的实际存量(5.2)~~ —— 2026-10-25 确认仍在用,见 3.1 +2. ~~`GetSectionDraw` 的返回值调用方到底期望什么(3.5)~~ —— 2026-10-25 核实全库调用点都忽略返回值,已按「返回新增个数」修正 +3. ~~`kCombination` 单元的实际存量(5.2)~~ —— 2026-10-25 确认仍在用,见 3.1 +4. `PreprocessForHlr` 的 `mat4` 双次变换是否刻意(3.12) +5. `HLR_CALC` 是否从 `m_mapSpecXData` 的序列化里排除(3.6):要动 `AecDbObjXDataMap` 公共类,且 `AecDbEwPipe` / `AecDbEwFitting` / `AecDbOpening` / `AecDbPipeHanger` 都在用它,需逐个确认有没有依赖它跨会话保持的地方 +6. `GetInterface` 数组版是否补 `dUnit`(3.7):补了之后米制图纸里所有走数组版的尺寸会放大 1000 倍,需确认 `subErase`、`PreprocessForHlr`、`Draw*Vlv2d` 的下游计算不受影响 +7. `AecDbEwFitting.cpp:16523` / `AecDbECFitting.cpp:8751` 的 `GetSectionDraw` 同样写反,是否一起改 --- @@ -599,6 +628,12 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 | `subErase` | 删除阀门/接头/普通设备各一次,确认只有阀门走合并管线 | | `HLR_CALC` | 剖切过程中保存再重开,设备 3D 仍可见 | | `copyFrom` | 复制粘贴竖放阀门,方向与图层保持 | +| `DrawHandFlg` | 液动阀(驱动类型 3)2D 符号旁显示 `Y` | +| `ProcessHlrResult` | 反复开关阀门剖切 2D 显示,不崩溃 | +| `clearGeoBuffer` | 改单元参数(box/cylinder/cone)后关闭对话框,几何立即更新 | +| `MakeBlockRefSet` | 剖切/2D 导出生成的块,插入点位于设备中心而不是原点 | +| `byJson` | JSON 导入设备,几何与参数正确 | +| `subErase` 的 `Find` | 删除普通设备后,相邻管线不被合并 | | 拖拽优化 | 拖夹点 10 秒,内存不涨、帧率稳定;松手后几何位置正确 | | 2D bbox | 各阀门 2D 符号方向、手柄位置与改前一致 | @@ -618,6 +653,6 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 1. ~~第一批 1~5(内存),单独一个 PR,可独立验证~~ —— 已完成,范围扩到 2.1~2.11 全部内存项,见 2.13 2. ~~第二批(`m_Combins` 存盘清空)~~ —— 已完成(PR #48),见 3.1、5.2 -3. 第一批 6~11(逻辑),单独一个 PR -4. 确认 5.4 剩下的两个问题 +3. ~~第一批 6~11(逻辑)~~ —— 已完成,范围扩到 3.2~3.14 共 10 项,见 5.1 +4. 确认 5.4 剩下的问题(3.6 `HLR_CALC` 序列化、3.7 `GetInterface` 单位、3.12 `mat4` 双次变换) 5. 第三批按 4.7 度量结果排序,一项一个 PR diff --git a/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp b/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp index ae6ce47..8184f5b 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp @@ -76,6 +76,9 @@ struct Point2d namespace { + //单个几何单元的参数块上限:正常只有几十字节到几十 KB,超出即视为图纸损坏 + const Adesk::Int32 kMaxXPrimDataSize = 16 * 1024 * 1024; + bool isValidExtents(const AcDbExtents &ext) { // 检查是否仍然处于初始化的“反转”状态 @@ -188,10 +191,24 @@ namespace pFiler->readInt32(&nSize); pSolid->m_nSize = nSize; + //单个单元的参数块只有几十字节到几十 KB,超出上限说明图纸损坏。 + //直接 new byte[巨量] 会当场失败,这里标记文件错误让整个 dwgInFields 退出 + if (pSolid->m_nSize > kMaxXPrimDataSize) + { + pSolid->m_nSize = 0; + pFiler->setFilerStatus(Acad::eInvalidInput); + return pSolid; + } + if (pSolid->m_nSize > 0) { pSolid->m_pData = new byte[pSolid->m_nSize]; - pFiler->readBytes(pSolid->m_pData, (Adesk::UInt32)pSolid->m_nSize); + if (pFiler->readBytes(pSolid->m_pData, (Adesk::UInt32)pSolid->m_nSize) != Acad::eOk) + { + delete[] (byte*)pSolid->m_pData; + pSolid->m_pData = NULL; + pSolid->m_nSize = 0; + } } //ID 存2个32为 @@ -825,8 +842,15 @@ namespace it = v.FindMember(_T("__pData__")); if (it == v.MemberEnd()) return false; GEO2JSON::binary br(it->value); - p->m_pData = new PVOID[br._len]; - ::memcpy(p->m_pData, br._data, sizeof(PVOID) * br._len); + //br._len 是字节数,与 __nSize__ 同单位。原来按 PVOID 个数分配、 + //再按 sizeof(PVOID)*len 拷贝,源缓冲区会越界读 7 倍。 + //两者不一致说明 JSON 被改过,按实际数据长度为准 + p->m_nSize = (int)br._len; + if (br._len > 0 && br._data != NULL) + { + p->m_pData = new byte[br._len]; + ::memcpy(p->m_pData, br._data, br._len); + } it = v.FindMember(_T("__nActiveInf__")); if (it == v.MemberEnd()) return false; @@ -2110,7 +2134,11 @@ Acad::ErrorStatus AecDbEwEquipment::subErase(Adesk::Boolean erasing) int nVal = 1; m_mapSpecXData.GetAt(PIPE_VALVE, nVal); - if (eSubType == eValve || sName.Find(_T("阀") ) != -1 || sName.Find(_T("接头"))) + //第三个条件原来写成 sName.Find(_T("接头")),Find 找不到返回 -1, + //非 0 即真,整个条件恒成立,删除任何设备都会走下面的合并管线逻辑 + if (eSubType == eValve + || sName.Find(_T("阀")) != -1 + || sName.Find(_T("接头")) != -1) { AecEqui::ValveType eVlvType = (AecEqui::ValveType)nVal; //if (eVlvType >= AecEqui::eGateVlv && eVlvType <= AecEqui::eJYF) @@ -2184,6 +2212,13 @@ Acad::ErrorStatus AecDbEwEquipment::copyFrom(const AcRxObject* pSrc) m_nInfActive = pImp->m_nInfActive; m_ptInsert = pImp->m_ptInsert; m_vtDir = pImp->m_vtDir; + + //这三个原来漏拷:m_bVert 决定阀门横放还是竖放(TransformEntity 要用), + //m_idDash / m_idCenter 是虚线与中心线所在的图层,丢了会跑到默认图层 + m_bVert = pImp->m_bVert; + m_idDash = pImp->m_idDash; + m_idCenter = pImp->m_idCenter; + AecEqui::XPrimData* pSolid = NULL; AecEqui::XPrimData* pSolid2 = NULL; @@ -2646,7 +2681,7 @@ Acad::ErrorStatus AecDbEwEquipment::DrawHandFlg(AcGiDraw &dc) const CString sFlag(_T("")); if (nVt == 1) sFlag = _T("M"); else if (nVt == 2) sFlag = _T("G"); - else sFlag == _T("Y"); + else sFlag = _T("Y"); //液动;原来写成 ==,sFlag 一直是空串 AecInterface inf1, inf2; GetInterface(0, inf1); @@ -4220,14 +4255,21 @@ int AecDbEwEquipment::GetBodyBox(AcDbExtents& ext) const Draw3d(dc); } - AcDbExtents _ext; + //原来恒返回 TRUE,调用方无法区分"没取到几何"。 + //_ext 也改为每轮新建,避免把上一轮的累积结果重复并入 + BOOL bRet(FALSE); for (size_t i = 0; i < ar3D.length(); i++) { AcDbEntity *p = (AcDbEntity*)ar3D[(int)i]; - p->getGeomExtents(_ext); + if (p == NULL) continue; + + AcDbExtents _ext; + if (p->getGeomExtents(_ext) != Acad::eOk) continue; + ext.addExt(_ext); + bRet = TRUE; } - return TRUE; + return bRet; } AecDbObjXDataMap* AecDbEwEquipment::GetSpecialtyData(AcDb::OpenMode bMode) @@ -12540,15 +12582,26 @@ void AecDbEwEquipment::setSectionID(const ESection &es, AcDbObjectId & id) //取中心位置为做块的插入位置 DLLIMPEXP bool MakeBlockRefSet(AcDbVoidPtrArray& arEntPtrs,const AcDbObjectId& idLay,Adesk::Boolean bDoSubent,LPCTSTR pszName,AcDbDatabase* pDb = NULL) { - AcDbExtents ext, extAdd; + AcDbExtents ext; AcDbEntity *pEnt = NULL; CString s; for (int i = 0;i < arEntPtrs.length();i++) { pEnt = (AcDbEntity*)arEntPtrs.at(i); - if (!AcDbBlockReference::cast(pEnt)) - pEnt->getGeomExtents(extAdd); - if (isValidExtents(ext)) + if (pEnt == NULL) continue; + + //块参照本身没有几何。原来不跳过,extAdd 会保留上一轮的值被重复累加 + if (AcDbBlockReference::cast(pEnt)) + continue; + + //每轮重新取,避免 getGeomExtents 失败时沿用上一轮的范围 + AcDbExtents extAdd; + if (pEnt->getGeomExtents(extAdd) != Acad::eOk) + continue; + + //原来判断的是累加器 ext:第一轮它还是空状态, + //第一个实体的范围永远加不进去 + if (isValidExtents(extAdd)) ext.addExt(extAdd); } @@ -12803,7 +12856,8 @@ int AecDbEwEquipment::GetSectionDraw(const AcGePoint3d& ptFr,const AcGePoint3d& GetSectionDraw(plan,vtTo,arRegionPtrs); int nCoundPre = arRegionPtrs.length(); - return (nCount - nCoundPre); + //返回本次新增的个数。原来写成 nCount - nCoundPre(调用前减调用后),恒为 0 或负数 + return (nCoundPre - nCount); } bool AecDbEwEquipment::GetPositionGrip(int nIndex, AecGripData *&pGrip) const @@ -12915,6 +12969,11 @@ bool AecDbEwEquipment::ByJson(const SHJson::WValue &v) void AecDbEwEquipment::clearGeoBuffer() { AssertWriteEnabled(); + + //调用方(改参数、改颜色之后)期望清掉缓存强制重建, + //原来函数体是空的,改完参数旧几何还在 + Clean2DBuffer(); + Clean3DBuffer(); } void AecDbEwEquipment::TransformEntity(AcDbEntity *p @@ -13179,13 +13238,14 @@ void AecDbEwEquipment::ProcessHlrResult(const AcArray &ar _ar.removeAll(); // 把 preAr 中的 region 生成的结果挑出来,不显示 + // 原来 erase(it) 之后仍然 ++it,迭代器已失效 std::map>::iterator it(_preAr.begin()); - for (; it != _preAr.end(); ++it) + while (it != _preAr.end()) { if (AcDbRegion::cast(it->first)) - { - _preAr.erase(it); - } + _preAr.erase(it++); //先取下一个迭代器再删当前 + else + ++it; } }