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

C++ 空基類優化 (EBO) 深度探索:原理、應用與 Boost 實戰

     編輯:關於C語言

一、EBO 背景:為什麼空類大小為 1?

C++ 標準規定:任何對象必須有唯一地址。因此,即使類內無非靜態數據成員、無虛函數、無虛基類(即「空類」),其 sizeof 也至少為 1 字節。但在繼承體系中,若基類為空,強制分配 1 字節會造成內存浪費。空基類優化 (Empty Base Optimization, EBO) 允許編譯器將空基類子對象的大小優化為 0,使其地址與派生類對象地址重合,從而節省空間。

二、EBO 適用場景全景圖

標準兼容的編譯器需處理單繼承、多繼承、菱形繼承等 8 種典型組合(圖示省略,見原文):

  • 單繼承:空→空 (EBO-1)、非空→空 (EBO-2)、優化傳遞性 (EBO-3/4)。
  • 多繼承:空+空 (EBO-5)、非空+空+空 (EBO-6)、空+非空+空 (EBO-7)、非空+非空+空 (EBO-8)。

完全支持 EBO 的編譯器應在所有情況下將空基類大小壓縮為 0。

三、EBO 實戰應用:從 compressed_pair 到策略類

1. 基礎優化:成員變量改為繼承

若類模板持有兩個可能為空的類型 T1, T2,直接作為成員會佔用空間。改為私有繼承即可啟用 EBO:

// 未優化:sizeof(EBO<Empty, Empty>) == 2
template<typename T1, typename T2> class EBO { T1 m_t1; T2 m_t2; };

// 優化後:sizeof(EBO<Empty, Empty>) == 1 (或 0 視編譯器對完整對象要求)
template<typename T1, typename T2> class EBO : private T1, private T2 { };

2. 進階挑戰:非類類型、同類型、非空類型混合

直接繼承無法處理:T1 為 int (非類類型)、T1 == T2 (同類型無法重複繼承)、或一方非空。需引入特化層 EBO_IMPL,配合類型萃取 (is_empty, is_same) 進行編譯期決策:

// 核心邏輯:根據 T1, T2 是否為空、是否相同,選擇繼承還是組合
template<typename T1, typename T2, bool Same, bool Empty1, bool Empty2>
struct EBO_IMPL; // 主模板未定義,強制特化

// Case: 不同類型,皆為空 -> 雙重繼承
template<typename T1, typename T2>
struct EBO_IMPL<T1, T2, false, true, true> : T1, T2 {};

// Case: 不同類型,T1 空,T2 非空 -> 繼承 T1,組合 T2
template<typename T1, typename T2>
struct EBO_IMPL<T1, T2, false, true, false> : T1 { T2 m_t2; };

// Case: 相同類型 (無法重複繼承) -> 退化為組合
template<typename T1, typename T2>
struct EBO_IMPL<T1, T2, true, false, false> { T1 m_t1; T2 m_t2; };
// ... 其他特化組合省略 ...

// 統一入口
template<typename T1, typename T2>
class EBO : public EBO_IMPL<T1, T2,
    boost::is_same<T1, T2>::value,
    boost::is_empty<T1>::value,
    boost::is_empty<T2>::value> { };

3. 終極方案:站在巨人肩上 —— boost::compressed_pair

Boost 已完美封裝上述邏輯並處理邊界情況(如 is_empty 實現細節、引用類型、CV 資格等)。生產代碼請直接使用:

#include <boost/compressed_pair.hpp>

template<typename T1, typename T2>
class EBO : public boost::compressed_pair<T1, T2> {
    // 獲得 first(), second() 訪問器,尺寸最優
};

四、EBO 的核心價值場景

  1. STL 標準庫實現:std::pair, std::tuple, 迭代器、函數對象基類 (iterator_traits, binary_function) 广泛依賴 EBO 避免空基類膨脹。
  2. 策略模式零開銷抽象:內存分配策略、線程同步策略、比較器策略等作為空基類注入,實現「無運行期開銷的多態」。
  3. 數據成員優化:類內含空類型成員時,同樣可通過「私有繼承 + 訪問器」模式壓縮對象布局。

五、總結

EBO 是 C++ 「零開銷抽象」哲學的典型體現。理解其觸發條件(空類、非虛繼承、非同類型重複繼承)與限制,並善用 boost::compressed_pair 或 C++20 的 [[no_unique_address]] 屬性,能讓你的高性能庫在內存佔用上更極致。

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