最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用C++實(shí)現(xiàn)的錯(cuò)誤信息收集器

 更新時(shí)間:2026年07月29日 09:08:45   作者:李遲  
還在為C++項(xiàng)目中錯(cuò)誤信息碎片化、重復(fù)記錄和特殊字符干擾而煩惱嗎,本文帶你深入剖析一個(gè)輕量級(jí)ErrorCollector類的設(shè)計(jì)與實(shí)現(xiàn),涵蓋去重存儲(chǔ)、字符清洗和靈活查詢等核心功能,讓你的錯(cuò)誤處理更高效、代碼更簡(jiǎn)潔,需要的朋友可以參考下

1. 背景

在大型C++項(xiàng)目的開發(fā)過程中,錯(cuò)誤處理是一個(gè)不容忽視的核心環(huán)節(jié)。年初筆者接手了一個(gè)工程,近幾個(gè)月在修改,發(fā)現(xiàn)其中的錯(cuò)誤信息處理比較凌亂,考慮到方便日后的自己的維護(hù),因此要進(jìn)行必要的重構(gòu)。缺乏統(tǒng)一錯(cuò)誤收集機(jī)制帶來以下一些困擾:

  • 信息碎片化:不同模塊各自定義錯(cuò)誤格式,日志散落在不同文件中,排查問題時(shí)需要手動(dòng)關(guān)聯(lián)
  • 重復(fù)記錄:同一個(gè)錯(cuò)誤可能被多個(gè)層級(jí)重復(fù)記錄,導(dǎo)致日志膨脹
  • 特殊字符干擾:錯(cuò)誤消息中包含的換行符、制表符破壞日志格式,影響后續(xù)分析
  • 缺乏分類:無法區(qū)分致命錯(cuò)誤、警告和普通提示信息

為了解決這些問題,筆者著手設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)輕量級(jí)的ErrorCollector類。本文將從需求分析、設(shè)計(jì)思路、實(shí)現(xiàn)細(xì)節(jié)到測(cè)試驗(yàn)證,完整分享這個(gè)組件的開發(fā)過程。

PS:近年來,筆者基本都會(huì)因其他共事的人升職、轉(zhuǎn)崗等原因接手不同性質(zhì)代碼工程,但還沒能力向他人移交工程或事務(wù)。從技術(shù)角度看,需要寫不同類別的代碼,是件好事,但從個(gè)人成長(zhǎng)角度看,不是個(gè)事,特別是處于年齡越來越大,頭發(fā)越來越白的尷尬的人生階段。

2. 設(shè)計(jì)思路

2.1 核心需求

經(jīng)過需求梳理,我們確定了以下核心功能點(diǎn):

  1. 去重存儲(chǔ):相同的錯(cuò)誤消息只保留一份,避免冗余
  2. 分類標(biāo)記:每條消息關(guān)聯(lián)一個(gè)錯(cuò)誤碼(0表示普通信息,非0表示錯(cuò)誤)
  3. 字符清洗:自動(dòng)移除\t、\n\r等特殊字符
  4. 靈活查詢:支持按類型(全部/僅錯(cuò)誤)、按錯(cuò)誤碼過濾查詢
  5. 空值安全:對(duì)空字符串和空指針有防護(hù)
  6. 簡(jiǎn)單易用:提供直觀的接口,且只有頭文件,減少使用成本

2.2 數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)

采用兩個(gè)并行的std::vector分別存儲(chǔ)錯(cuò)誤碼和消息文本:

std::vector<int> m_code;          // 錯(cuò)誤碼列表
std::vector<std::string> m_list;  // 消息列表(與m_code一一對(duì)應(yīng))

這種設(shè)計(jì)的優(yōu)勢(shì)有以下幾點(diǎn):

  • 索引對(duì)應(yīng):通過相同下標(biāo)關(guān)聯(lián)錯(cuò)誤碼和消息,無需額外的映射結(jié)構(gòu)(注意索引需大于等于0)
  • 順序保留:保持添加順序,便于追溯問題發(fā)生的時(shí)間線
  • 內(nèi)存友好:相比std::mapstd::unordered_map,內(nèi)存開銷更小

去重機(jī)制則通過std::findm_list中線性查找實(shí)現(xiàn)。雖然時(shí)間復(fù)雜度為O(n),但考慮到錯(cuò)誤收集場(chǎng)景下消息數(shù)量通常有限(一般不超過幾十條),這種實(shí)現(xiàn)足夠高效且代碼簡(jiǎn)潔。

2.3 接口設(shè)計(jì)原則

  • 重載友好:同時(shí)支持std::stringconst char*參數(shù),適應(yīng)不同使用場(chǎng)景
  • 默認(rèn)參數(shù)code參數(shù)默認(rèn)為0,簡(jiǎn)化普通信息記錄的調(diào)用
  • 防御性編程:在函數(shù)入口進(jìn)行參數(shù)校驗(yàn),提前返回避免無效操作
  • const正確性:查詢接口標(biāo)記為const,確保不修改對(duì)象狀態(tài)

3. 實(shí)踐

3.1 源碼

ErrorCollector.h文件代碼如下:

#include <algorithm> 
#include <vector>
#include <unordered_set>
#include <string>

// 錯(cuò)誤信息、過程信息記錄器
class ErrorCollector {
public:
    // 構(gòu)造函數(shù),初始化變量為空
    ErrorCollector() {
        m_code.clear();
        m_list.clear();
    }
    
    // 析構(gòu)函數(shù)(可選)
    ~ErrorCollector() {
        m_code.clear();
        m_list.clear();
    }

    void AddInfo(const std::string& msg1, int code = 0) {
        // 判斷字符串是否為空
        if (msg1.empty()) {
            return;
        }
        std::string msg = msg1;

        msg.erase(std::remove_if(msg.begin(), msg.end(),
        [](char c) { return c == '\t' || c == '\n' || c == '\r'; }), 
        msg.end());

        // 刪除特殊字符后再次判斷是否為空
        if (msg.empty()) {
            return;
        }
        if (std::find(m_list.begin(), m_list.end(), msg) == m_list.end()) {
            m_code.push_back(code);
            m_list.push_back(msg);
        }
    }
    void AddInfo(const char* msg1, int code = 0) {
        // 判斷指針是否為空,以及字符串是否為空
        if (msg1 == nullptr || msg1[0] == '\0') {
            return;
        }
        std::string msg = msg1;
        AddInfo(msg, code);
    }

    // 返回豎線分隔的字符串,格式:錯(cuò)誤1 | 錯(cuò)誤2 | 錯(cuò)誤3
    // all 表示所有的信息,如只返回錯(cuò)誤,設(shè)置為false
    std::string GetInfos(bool all = true) const {
        std::string result;
        int cnt = 0;
        for (size_t i = 0; i < m_list.size(); i++) {
            if (!all && m_code[i] == 0) {
                continue;
            }
            if (cnt > 0) {
                result += " | ";
            }
            cnt++;
            result += m_list[i];
        }
        
        if (!result.empty() && result.back() == '|') {
            result.pop_back();
        }
        return result;
    }
    // 同上,指定code
    std::string GetInfoByCode(int code) const {
        std::string result;
        int cnt = 0;
        for (size_t i = 0; i < m_list.size(); i++) {
            if (m_code[i] != code) {
                continue;
            }
            if (cnt > 0) {
                result += " | ";
            }
            cnt++;
            result += m_list[i];
        }
        
        if (!result.empty() && result.back() == '|') {
            result.pop_back();
        }
        return result;
    }
    std::string GetCodes() const {
        std::string result;
        int cnt = 0;
        for (size_t i = 0; i < m_code.size(); i++) {
            if (m_code[i] == 0) {
                continue;
            }
            if (cnt > 0) {
                result += "|"; // 不要空格緊湊一些
            }
            cnt++;
            result += std::to_string(m_code[i]);
        }
        if (!result.empty() && result.back() == '|') {
            result.pop_back();
        }
        return result;
    }
    // 可指定忽略的code
    std::string GetCodes(int skipCode) const {
        std::string result;
        int cnt = 0;
        for (size_t i = 0; i < m_code.size(); i++) {
            if (m_code[i] == 0 || m_code[i] == skipCode) {
                continue;
            }
            if (cnt > 0) {
                result += "|"; // 不要空格緊湊一些
            }
            cnt++;
            result += std::to_string(m_code[i]);
        }
        if (!result.empty() && result.back() == '|') {
            result.pop_back();
        }
        return result;
    }

    bool Empty() {return m_list.empty();}

private:
    std::vector<int> m_code;
    std::vector<std::string> m_list;
};

3.2 關(guān)鍵實(shí)現(xiàn)解析

特殊字符清洗

msg.erase(std::remove_if(msg.begin(), msg.end(),
    [](char c) { return c == '\t' || c == '\n' || c == '\r'; }), 
    msg.end());

這里使用了經(jīng)典的"erase-remove"慣用法,高效地移除了三種常見的格式干擾字符。清洗后再判斷消息是否為空,確保不會(huì)存儲(chǔ)僅由特殊字符組成的無效消息。

去重邏輯

if (std::find(m_list.begin(), m_list.end(), msg) == m_list.end()) {
    m_code.push_back(code);
    m_list.push_back(msg);
}

值得注意的是,此處考慮的設(shè)計(jì)決策是:去重基于消息內(nèi)容,而不是消息+錯(cuò)誤碼的組合。這意味著如果同一個(gè)錯(cuò)誤消息先后以不同的錯(cuò)誤碼添加,只有第一次會(huì)被保留,后續(xù)的添加會(huì)被忽略。這種設(shè)計(jì)在某些場(chǎng)景下可能丟失錯(cuò)誤碼信息,但換來的是消息列表的簡(jiǎn)潔性。在實(shí)際使用中,我們約定錯(cuò)誤消息應(yīng)該包含足夠的上下文信息,使得重復(fù)消息確實(shí)不需要再次記錄。

輸出格式控制

if (cnt > 0) {
    result += " | ";
}
cnt++;
result += m_list[i];

此處通過計(jì)數(shù)器控制分隔符的插入位置,避免在字符串開頭或結(jié)尾出現(xiàn)多余的分隔符。GetCodes方法中則使用更緊湊的"|"(無空格)作為分隔符,方便后續(xù)解析。

3.3 使用示例

ErrorCollector collector;

// 記錄普通信息
collector.AddInfo("開始數(shù)據(jù)遷移");

// 記錄錯(cuò)誤
collector.AddInfo("連接數(shù)據(jù)庫失敗", 1001);
collector.AddInfo("讀取配置文件異常", 1002);

// 獲取所有信息(包含提示和錯(cuò)誤)
std::string all = collector.GetInfos(true);
// 輸出: "開始數(shù)據(jù)遷移 | 連接數(shù)據(jù)庫失敗 | 讀取配置文件異常"

// 僅獲取錯(cuò)誤信息
std::string errors = collector.GetInfos(false);
// 輸出: "連接數(shù)據(jù)庫失敗 | 讀取配置文件異常"

// 獲取錯(cuò)誤碼列表
std::string codes = collector.GetCodes();
// 輸出: "1001|1002"

// 按錯(cuò)誤碼查詢
std::string info = collector.GetInfoByCode(1001);
// 輸出: "連接數(shù)據(jù)庫失敗"

3.4 應(yīng)用場(chǎng)景

ErrorCollector在以下場(chǎng)景中特別有用:

  1. API參數(shù)校驗(yàn):收集所有校驗(yàn)失敗的信息,一次性返回給調(diào)用方
  2. 批量操作:執(zhí)行多個(gè)獨(dú)立操作時(shí),收集所有異常而非遇到第一個(gè)錯(cuò)誤就中斷
  3. 配置加載:加載配置文件時(shí),記錄所有格式錯(cuò)誤或缺失的配置項(xiàng)
  4. 單元測(cè)試:收集測(cè)試過程中的斷言失敗信息

4. 測(cè)試

4.1 測(cè)試代碼

測(cè)試代碼文件main.cpp:

#include <iostream>
#include "ErrorCollector.h"

void printTestResult(const std::string& testName, bool passed) {
    std::cout << (passed ? "[PASS]" : "[FAIL]") << " " << testName << std::endl;
}

int main() {
    ErrorCollector collector;
    
    // 測(cè)試1:基本添加和獲取
    std::cout << "\n=== 測(cè)試1:基本功能 ===" << std::endl;
    collector.AddInfo("數(shù)據(jù)庫連接失敗", 1001);
    collector.AddInfo("配置文件缺失", 1002);
    collector.AddInfo("用戶認(rèn)證超時(shí)", 0);  // code為0表示提示信息
    
    std::string infos = collector.GetInfos(true);
    std::cout << "所有信息: " << infos << std::endl;
    std::cout << "僅錯(cuò)誤: " << collector.GetInfos(false) << std::endl;
    std::cout << "錯(cuò)誤碼: " << collector.GetCodes() << std::endl;
    printTestResult("基本功能", infos == "數(shù)據(jù)庫連接失敗 | 配置文件缺失 | 用戶認(rèn)證超時(shí)");
    
    // 測(cè)試2:去重功能
    std::cout << "\n=== 測(cè)試2:去重功能 ===" << std::endl;
    ErrorCollector collector2;
    collector2.AddInfo("重復(fù)錯(cuò)誤", 100);
    collector2.AddInfo("重復(fù)錯(cuò)誤", 200);  // 相同消息,不同code
    collector2.AddInfo("唯一錯(cuò)誤", 300);
    
    std::string result = collector2.GetInfos(true);
    std::cout << "去重后結(jié)果: " << result << std::endl;
    std::cout << "錯(cuò)誤碼: " << collector2.GetCodes() << std::endl;
    printTestResult("去重功能", result == "重復(fù)錯(cuò)誤 | 唯一錯(cuò)誤" && collector2.GetCodes() == "100|300");
    
    // 測(cè)試3:空字符串和特殊字符
    std::cout << "\n=== 測(cè)試3:空值和特殊字符過濾 ===" << std::endl;
    ErrorCollector collector3;
    collector3.AddInfo("", 100);
    collector3.AddInfo("\t\n\r", 200);
    collector3.AddInfo("有效消息", 300);
    collector3.AddInfo(nullptr, 400);
    
    std::string result3 = collector3.GetInfos(true);
    std::cout << "過濾后結(jié)果: " << result3 << std::endl;
    printTestResult("空值過濾", result3 == "有效消息");
    printTestResult("空狀態(tài)檢測(cè)", !collector3.Empty());
    
    // 測(cè)試4:特殊字符清理(制表符、換行符)
    std::cout << "\n=== 測(cè)試4:特殊字符清理 ===" << std::endl;
    ErrorCollector collector4;
    collector4.AddInfo("消息\t包含\t制表符", 100);
    collector4.AddInfo("第一行\(zhòng)n第二行\(zhòng)r\n", 200);
    
    std::string result4 = collector4.GetInfos(true);
    std::cout << "清理后結(jié)果: " << result4 << std::endl;
    printTestResult("制表符清理", result4 == "消息包含制表符 | 第一行第二行");
    
    // 測(cè)試5:按錯(cuò)誤碼過濾
    std::cout << "\n=== 測(cè)試5:按錯(cuò)誤碼獲取 ===" << std::endl;
    ErrorCollector collector5;
    collector5.AddInfo("錯(cuò)誤A", 100);
    collector5.AddInfo("提示B", 0);
    collector5.AddInfo("錯(cuò)誤C", 200);
    collector5.AddInfo("錯(cuò)誤D", 300);
    
    std::cout << "錯(cuò)誤碼100的信息: " << collector5.GetInfoByCode(100) << std::endl;
    std::cout << "跳過錯(cuò)誤碼200: " << collector5.GetCodes(200) << std::endl;
    printTestResult("按碼獲取", collector5.GetInfoByCode(100) == "錯(cuò)誤A");
    printTestResult("跳過碼獲取", collector5.GetCodes(200) == "100|300");
    
    // 測(cè)試6:格式驗(yàn)證
    std::cout << "\n=== 測(cè)試6:輸出格式驗(yàn)證 ===" << std::endl;
    ErrorCollector collector6;
    collector6.AddInfo("A", 1);
    collector6.AddInfo("B", 2);
    collector6.AddInfo("C", 3);
    
    std::string result6 = collector6.GetInfos(true);
    std::cout << "格式結(jié)果: " << result6 << std::endl;
    bool formatOk = (result6 == "A | B | C") && 
                    (result6.back() != '|') && 
                    (result6.front() != '|');
    printTestResult("格式正確", formatOk);
    
    // 測(cè)試7:空狀態(tài)檢測(cè)
    std::cout << "\n=== 測(cè)試7:空狀態(tài)檢測(cè) ===" << std::endl;
    ErrorCollector collector7;
    std::cout << "初始Empty: " << (collector7.Empty() ? "true" : "false") << std::endl;
    collector7.AddInfo("測(cè)試", 100);
    std::cout << "添加后Empty: " << (collector7.Empty() ? "true" : "false") << std::endl;
    printTestResult("空狀態(tài)檢測(cè)", collector7.Empty() == false);
    
    // 測(cè)試8:大量數(shù)據(jù)性能
    std::cout << "\n=== 測(cè)試8:大量數(shù)據(jù)性能 ===" << std::endl;
    ErrorCollector collector8;
    for (int i = 0; i < 1000; i++) {
        collector8.AddInfo("錯(cuò)誤_" + std::to_string(i), i);
    }
    std::string result8 = collector8.GetInfos(true);
    bool hasError500 = result8.find("錯(cuò)誤_500") != std::string::npos;
    std::cout << "包含第500條: " << (hasError500 ? "是" : "否") << std::endl;
    printTestResult("大量數(shù)據(jù)處理", hasError500);
    
    std::cout << "\n=== 所有測(cè)試完成 ===" << std::endl;
    return 0;
}

編譯命令:

g++ -std=c++11  main.cpp

執(zhí)行輸出結(jié)果:

# ./a.out

=== 測(cè)試1:基本功能 ===
所有信息: 數(shù)據(jù)庫連接失敗 | 配置文件缺失 | 用戶認(rèn)證超時(shí)
僅錯(cuò)誤: 數(shù)據(jù)庫連接失敗 | 配置文件缺失
錯(cuò)誤碼: 1001|1002
[PASS] 基本功能

=== 測(cè)試2:去重功能 ===
去重后結(jié)果: 重復(fù)錯(cuò)誤 | 唯一錯(cuò)誤
錯(cuò)誤碼: 100|300
[PASS] 去重功能

=== 測(cè)試3:空值和特殊字符過濾 ===
過濾后結(jié)果: 有效消息
[PASS] 空值過濾
[PASS] 空狀態(tài)檢測(cè)

=== 測(cè)試4:特殊字符清理 ===
清理后結(jié)果: 消息包含制表符 | 第一行第二行
[PASS] 制表符清理

=== 測(cè)試5:按錯(cuò)誤碼獲取 ===
錯(cuò)誤碼100的信息: 錯(cuò)誤A
跳過錯(cuò)誤碼200: 100|300
[PASS] 按碼獲取
[PASS] 跳過碼獲取

=== 測(cè)試6:輸出格式驗(yàn)證 ===
格式結(jié)果: A | B | C
[PASS] 格式正確

=== 測(cè)試7:空狀態(tài)檢測(cè) ===
初始Empty: true
添加后Empty: false
[PASS] 空狀態(tài)檢測(cè)

=== 測(cè)試8:大量數(shù)據(jù)性能 ===
包含第500條: 是
[PASS] 大量數(shù)據(jù)處理

=== 所有測(cè)試完成 ===

4.2 關(guān)鍵測(cè)試用例

用例1:基本功能驗(yàn)證

collector.AddInfo("數(shù)據(jù)庫連接失敗", 1001);
collector.AddInfo("配置文件缺失", 1002);
collector.AddInfo("用戶認(rèn)證超時(shí)", 0);

用例2:去重驗(yàn)證

    collector2.AddInfo("重復(fù)錯(cuò)誤", 100);
    collector2.AddInfo("重復(fù)錯(cuò)誤", 200);  // 相同消息,不同code
    collector2.AddInfo("唯一錯(cuò)誤", 300);

用例3:特殊字符清理

    ErrorCollector collector4;
    collector4.AddInfo("消息\t包含\t制表符", 100);
    collector4.AddInfo("第一行\(zhòng)n第二行\(zhòng)r\n", 200);

4.3 測(cè)試結(jié)論

所有測(cè)試用例全部通過,驗(yàn)證了實(shí)現(xiàn)的正確性和健壯性。

測(cè)試項(xiàng)預(yù)期結(jié)果實(shí)際結(jié)果狀態(tài)
基本添加和獲取正確存儲(chǔ)和檢索通過?
消息去重相同消息只保留一個(gè)通過?
空值過濾空字符串被忽略通過?
特殊字符清理移除\t\n\r通過?
按錯(cuò)誤碼獲取正確過濾通過?
跳過指定錯(cuò)誤碼正確排除通過?
輸出格式豎線分隔,無多余符號(hào)通過?
空狀態(tài)檢測(cè)狀態(tài)正確通過?
性能測(cè)試1000條數(shù)據(jù)正常處理通過?

5. 其它說明

ErrorCollector雖然是一個(gè)簡(jiǎn)單的工具類,但它在實(shí)際項(xiàng)目中發(fā)揮了重要作用。以下是一些要點(diǎn)說明和未來改進(jìn)方向:

  1. 其它信息收集ErrorCollector雖然名為錯(cuò)誤收集器,但通過創(chuàng)建多個(gè)副本,可實(shí)現(xiàn)其它信息的收集。另外,可以根據(jù)
  2. 線程安全:在多線程環(huán)境下,需要添加互斥鎖保護(hù)
  3. 容量限制:防止錯(cuò)誤消息無限增長(zhǎng),可以設(shè)置最大容量
  4. 持久化:支持將錯(cuò)誤信息序列化到文件或數(shù)據(jù)庫

6. 小結(jié)

錯(cuò)誤收集看似簡(jiǎn)單,但設(shè)計(jì)一個(gè)好用、健壯的錯(cuò)誤收集器需要對(duì)使用場(chǎng)景有深入理解。ErrorCollector的實(shí)踐證明,即使是小型工具類,只要設(shè)計(jì)得當(dāng),也能在項(xiàng)目中發(fā)揮"四兩撥千斤"的效果。

在軟件開發(fā)中,我們常常追求復(fù)雜而全面的解決方案,但有時(shí)候,一個(gè)簡(jiǎn)潔、專注的工具可能更符合"夠用就好"的工程哲學(xué)。正如這個(gè)錯(cuò)誤收集器所展示的:在正確的抽象層次上,解決正確的問題,就是好的設(shè)計(jì)。

以上就是使用C++實(shí)現(xiàn)的錯(cuò)誤信息收集器的詳細(xì)內(nèi)容,更多關(guān)于C++錯(cuò)誤信息收集器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

台南县| 凤翔县| 吉安县| 花莲县| 兴安盟| 城市| 高阳县| 阿克苏市| 清河县| 和平县| 抚顺市| 岑巩县| 潞城市| 九龙县| 石台县| 仲巴县| 克什克腾旗| 新疆| 偃师市| 和平县| 申扎县| 西平县| 扎兰屯市| 许昌市| 科技| 通州市| 鄱阳县| 枣阳市| 衡阳县| 贵溪市| 苏尼特右旗| 江孜县| 石渠县| 光山县| 盐山县| 日喀则市| 噶尔县| 新津县| 启东市| 安岳县| 睢宁县|