首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

MFC 單文檔序列化中「刪除操作」的正確實現策略:偽刪除與真刪除

     編輯:程式設計綜合問答

核心誤區

很多初學者嘗試在 `OnDelete()` 中直接 `delete pObj`,發現文件大小不變、數據未真正移除。根本原因:**`delete` 僅釋放 C++ 堆內存,不會自動修改已序列化的磁盤文件**。MFC 序列化機制是「整文件覆寫」,單獨刪除對象無法原地修改文件結構。

方案一:偽刪除—— 工業界通用做法

核心思想

在數據模型中增加 `bool m_bDeleted` 標記字段,刪除時僅置 `true`,序列化時跳過該標記對象。

代碼實現

// 模型類
class CMyDoc : public CDocument {
    struct Item {
        CString name;
        bool deleted = false;  // 新增標記
        void Serialize(CArchive& ar) {
            ar << name << deleted;
        }
    };
    CArray m_items;
    
    void DeleteItem(int index) {
        if (index >= 0 && index < m_items.GetSize())
            m_items[index].deleted = true;  // 偽刪除
        SetModifiedFlag();
    }
    
    void Serialize(CArchive& ar) override {
        if (ar.IsStoring()) {
            int count = 0;
            for (auto& item : m_items) if (!item.deleted) ++count;
            ar << count;
            for (auto& item : m_items) 
                if (!item.deleted) item.Serialize(ar);
        } else {
            int count; ar >> count;
            m_items.SetSize(count);
            for (auto& item : m_items) item.Serialize(ar);
        }
    }
};

優缺點

  • ✅ 極快:O(1) 標記,無需重寫文件
  • ✅ 可撤銷:輕鬆實現「恢復刪除」
  • ⚠️ 文件體積不減:長期使用需定期「壓縮整理」

方案二:真刪除—— 重新序列化整個文檔

適用場景

數據量小(< 10MB)、刪除頻率低、必須物理釋放磁盤空間。

實現步驟

  1. 從內存容器中 `RemoveAt(index)` 真正移除對象
  2. 調用 `CDocument::OnSaveDocument(path)` 觸發完整序列化
  3. MFC 會自動創建臨時文件 → 寫入新數據 → 替換原文件

關鍵代碼

void CMyDoc::OnDeleteItem(int index) {
    if (index < 0 || index >= m_items.GetSize()) return;
    m_items.RemoveAt(index);  // 真正從內存移除
    SetModifiedFlag();
    // 可選:立即保存,或等用戶點「保存」
    // OnSaveDocument(GetPathName()); 
}

方案對比與選型建議

維度偽刪除真刪除
實現難度低(加字段+判斷)低(RemoveAt+Save)
性能極高隨文件大小線性增長
撤銷支持原生支持需額外實現撤銷棧
磁盤空間不自動釋放即時釋放
推薦場景大多數桌面應用嵌入式/極小文件

進階:定期壓縮整理(偽刪除的補完)

在「文件 → 整理」菜單或退出程序時,遍歷內存數據,重新序列化一次,物理清除已標記對象:

void CMyDoc::Compact() {
    CArray alive;
    for (auto& item : m_items) if (!item.deleted) alive.Add(item);
    m_items = alive;
    OnSaveDocument(GetPathName());
}

總結

MFC 序列化本質是「整文件覆寫」,**單對象 `delete` 無法修改磁盤**。工程上首選偽刪除(標記法),配合定期壓縮,兼顧性能、可撤銷、實現簡單;僅在極小文件或強合規場景下採用真刪除(重寫文件)。理解這一機制,能避免在文檔類應用中走彎路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved