首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ std::sort 仿函數(Functor)完整指南:狀態保持與嚴格弱序

     編輯:關於C語言

從函數指標到仿函數的覺醒

習慣 qsort 函數指標的開發者,初次使用 std::sort 時常直接傳遞函數指標。雖然語法可行,但錯失了仿函數(Function Object / Functor)的核心優勢——攜帶狀態。

實戰場景:動態排序規則

需對表格排序,每欄位可能升序/降序、類型不同,比較邏輯需依據執行期資訊(如欄位型別、排序方向)決定。若用普通函數或靜態函數,無法存取物件成員變數;若用類別成員函數,又不符合 std::sort 的呼叫慣例。

仿函數解決方案

class MyClass {
    // ... 類別成員資料 ...

    struct DoCompare {
        // 建構子接收外部狀態(如 this 指標)
        DoCompare(const MyClass& info) : m_info(info) {}

        const MyClass& m_info;  // 保存狀態參考

        // 重載 operator() 使物件可像函數一樣呼叫
        bool operator()(const int& i1, const int& i2) {
            // 使用 m_info 進行比較邏輯判斷
            // return 比較結果;
        }
    };

    void doSort() {
        // 建立仿函數物件,傳入 *this 作為狀態
        std::sort(arr, arr + someSize, DoCompare(*this));
    }
};

核心優勢分析

特性函數指標仿函數
攜帶狀態❌ 無法✅ 透過成員變數
內聯優化❌ 難以內聯✅ 編譯器易內聯
類型安全⚠️ 需強制轉型✅ 模板推導類型
效能較低通常更高

關鍵陷阱:嚴格弱序

std::sort 要求比較函數滿足 Strict Weak Ordering:

  • 不可自反:comp(x, x) == false
  • 傳遞性:comp(a, b) && comp(b, c) → comp(a, c)
  • 等價傳遞性:!comp(a,b) && !comp(b,a) 視為等價,等價關係具傳遞性

常見錯誤:直接取反實現降序

// ❌ 錯誤:違反嚴格弱序
bool descBad(int a, int b) { return a >= b; }

// ✅ 正確:嚴格小於
bool descGood(int a, int b) { return a > b; }

原因: >= 的反面不是 <,而是 <=。若 a == b,descBad 回傳 true,導致 comp(a,b) && comp(b,a) 同時為真,違反不可自反性,可能造成標準庫實作存取越界(如無限遞迴或記憶體錯誤)。

最佳實踐建議

  1. 優先使用 Lambda (C++11):std::sort(v.begin(), v.end(), [&](auto a, auto b){ return a > b; });
  2. 複雜邏輯用仿函數類別:需攜帶多個狀態、可重用時。
  3. 永遠驗證比較函數:確保滿足嚴格弱序,必要時寫單元測試。
  4. 避免繼承 std::binary_function:C++11 已棄用,C++17 移除。

總結

仿函數是 C++ 泛型演算法的靈魂,理解其「可呼叫物件」本質與狀態封裝能力,能解決函數指標無法處理的動態比較需求。記住:比較函數必須實作嚴格弱序,否則行為未定義。

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