More Effective C++ 條款26:限制某個類所能產生的對象數量

More Effective C++ 條款26:限制某個類所能產生的對象數量


核心思想通過控制類的實例化過程,限制程序中該類的對象數量,可以防止資源過度使用,確保系統資源合理分配,并實現單例或有限實例模式。

🚀 1. 問題本質分析

1.1 對象數量限制的需求

  • 單例模式:確保一個類只有一個實例,并提供全局訪問點
  • 有限資源管理:例如數據庫連接池、線程池等,需要限制實例數量以避免資源耗盡
  • 唯一性約束:某些類在邏輯上應該是唯一的,比如應用程序的配置管理器

1.2 實現限制的挑戰

  • 防止直接實例化:需要攔截所有創建對象的途徑(構造函數、拷貝構造、賦值操作等)
  • 繼承帶來的復雜性:派生類可能無意中創建多個實例
  • 線程安全:在多線程環境中,需要安全地控制實例數量
// 基礎示例:單例模式
class Singleton {
public:static Singleton& getInstance() {static Singleton instance;  // 局部靜態變量,C++11保證線程安全return instance;}// 刪除拷貝構造函數和賦值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:Singleton() = default;  // 私有構造函數~Singleton() = default;
};

📦 2. 問題深度解析

2.1 對象計數技術

// 使用靜態計數限制對象數量
class LimitedInstances {
public:LimitedInstances() {if (count >= maxInstances) {throw std::runtime_error("Too many instances");}++count;}~LimitedInstances() {--count;}// 禁止拷貝和賦值,因為拷貝會增加實例,但這里我們不允許LimitedInstances(const LimitedInstances&) = delete;LimitedInstances& operator=(const LimitedInstances&) = delete;static int getCount() { return count; }private:static int count;static const int maxInstances = 5;  // 最大實例數
};int LimitedInstances::count = 0;

2.2 繼承條件下的限制

// 基類限制派生類的實例數量
class Base {
protected:Base() {if (count >= maxInstances) {throw std::runtime_error("Too many instances");}++count;}~Base() {--count;}// 允許移動語義,但同樣要控制數量?實際上移動構造不會增加計數,因為它是從現有對象構造,但我們這里禁止拷貝和移動Base(const Base&) = delete;Base(Base&&) = delete;Base& operator=(const Base&) = delete;Base& operator=(Base&&) = delete;private:static int count;static const int maxInstances = 10;
};int Base::count = 0;class Derived : public Base {// 派生類會調用Base的構造函數,因此受Base的計數限制
};

2.3 使用代理控制構造

// 通過代理類控制實例創建
class InstanceController;class LimitedClass {
private:LimitedClass() = default;  // 私有構造函數// 友元類,允許代理訪問私有構造函數friend class InstanceController;
};class InstanceController {
public:LimitedClass& createInstance() {if (count >= maxInstances) {throw std::runtime_error("Too many instances");}++count;// 使用智能指針管理,這里簡單返回靜態實例的引用,實際可能需要更復雜的邏輯static LimitedClass instance;  // 注意:這里只是示例,實際可能需要多個實例return instance;}void releaseInstance() {--count;// 如果需要管理多個實例,則需要更復雜的邏輯}private:static int count;static const int maxInstances = 3;
};int InstanceController::count = 0;

?? 3. 解決方案與最佳實踐

3.1 單例模式的變體

// 帶生命期控制的單例
template<typename T>
class Singleton {
public:static T& getInstance() {if (!instance) {instance = new T();}return *instance;}// 允許手動銷毀單例,注意線程安全和重復銷毀問題static void destroyInstance() {delete instance;instance = nullptr;}protected:Singleton() = default;virtual ~Singleton() = default;// 禁止拷貝和移動Singleton(const Singleton&) = delete;Singleton(Singleton&&) = delete;Singleton& operator=(const Singleton&) = delete;Singleton& operator=(Singleton&&) = delete;private:static T* instance;
};template<typename T>
T* Singleton<T>::instance = nullptr;// 使用示例
class MyClass : public Singleton<MyClass> {friend class Singleton<MyClass>;  // 允許Singleton訪問MyClass的私有構造函數
private:MyClass() = default;
};

3.2 對象計數與異常安全

// 使用RAII管理對象計數
class InstanceCounter {
public:explicit InstanceCounter(int max) : maxInstances(max) {if (count >= maxInstances) {throw std::runtime_error("Too many instances");}++count;}~InstanceCounter() {--count;}static int getCount() { return count; }// 禁止拷貝和移動InstanceCounter(const InstanceCounter&) = delete;InstanceCounter(InstanceCounter&&) = delete;InstanceCounter& operator=(const InstanceCounter&) = delete;InstanceCounter& operator=(InstanceCounter&&) = delete;private:static int count;const int maxInstances;
};int InstanceCounter::count = 0;// 在需要限制的類中使用
class Limited {
public:Limited() : counter(5) {}  // 最多5個實例private:InstanceCounter counter;
};

3.3 使用std::unique_ptr管理有限實例

// 對象池模式
template<typename T, int MaxInstances>
class ObjectPool {
public:template<typename... Args>static std::unique_ptr<T, void(*)(T*)> acquire(Args&&... args) {if (count >= MaxInstances) {throw std::runtime_error("Too many instances");}++count;// 自定義刪除器,在釋放時減少計數return std::unique_ptr<T, void(*)(T*)>(new T(std::forward<Args>(args)...), [](T* ptr) {delete ptr;--count;});}static int getCount() { return count; }private:static std::atomic<int> count;  // 多線程安全
};template<typename T, int MaxInstances>
std::atomic<int> ObjectPool<T, MaxInstances>::count(0);// 使用示例
class ExpensiveResource {
public:ExpensiveResource() { /* 占用大量資源的操作 */ }void use() { /* 使用資源 */ }
};void useResource() {auto resource = ObjectPool<ExpensiveResource, 10>::acquire();resource->use();// 當resource離開作用域,自動釋放并減少計數
}

3.4 線程安全的實例計數

// 使用原子操作和互斥鎖確保線程安全
class ThreadSafeLimited {
public:ThreadSafeLimited() {std::lock_guard<std::mutex> lock(mutex);if (count >= maxInstances) {throw std::runtime_error("Too many instances");}++count;}~ThreadSafeLimited() {std::lock_guard<std::mutex> lock(mutex);--count;}// 禁止拷貝和移動ThreadSafeLimited(const ThreadSafeLimited&) = delete;ThreadSafeLimited(ThreadSafeLimited&&) = delete;ThreadSafeLimited& operator=(const ThreadSafeLimited&) = delete;ThreadSafeLimited& operator=(ThreadSafeLimited&&) = delete;static int getCount() {std::lock_guard<std::mutex> lock(mutex);return count;}private:static std::atomic<int> count;static const int maxInstances = 5;static std::mutex mutex;
};std::atomic<int> ThreadSafeLimited::count(0);
std::mutex ThreadSafeLimited::mutex;

💡 關鍵實踐原則

  1. 明確限制策略
    在設計時決定是單例還是有限實例,以及如何處理邊界情況(如超過限制時拋出異常還是返回nullptr)
  2. 考慮所有權和生命周期
    使用智能指針管理實例,確保異常安全且避免內存泄漏
  3. 線程安全是關鍵
    多線程環境下,必須使用原子操作或互斥鎖保護計數變量
  4. 防止拷貝和移動
    刪除拷貝構造函數和賦值操作符,避免意外創建新實例

對象數量限制模式選擇

// 策略模式選擇限制方式
template<typename T, template<typename> class CountingPolicy = SimpleCounting>
class LimitedObject : private CountingPolicy<T> {
public:template<typename... Args>LimitedObject(Args&&... args) : CountingPolicy<T>(std::forward<Args>(args)...) {CountingPolicy<T>::increment();  // 策略增加計數}~LimitedObject() {CountingPolicy<T>::decrement();}// 其他接口...
};// 計數策略
template<typename T>
class SimpleCounting {
protected:void increment() {if (++count > maxCount) {throw std::runtime_error("Too many instances");}}void decrement() {--count;}private:static int count;static const int maxCount = 1;  // 默認為單例
};template<typename T>
int SimpleCounting<T>::count = 0;

單例模式的線程安全實現(C++11之后)

// Meyer's Singleton: C++11保證靜態局部變量初始化線程安全
class MeyerSingleton {
public:static MeyerSingleton& getInstance() {static MeyerSingleton instance;return instance;}// 刪除拷貝和移動MeyerSingleton(const MeyerSingleton&) = delete;MeyerSingleton(MeyerSingleton&&) = delete;MeyerSingleton& operator=(const MeyerSingleton&) = delete;MeyerSingleton& operator=(MeyerSingleton&&) = delete;private:MeyerSingleton() = default;~MeyerSingleton() = default;
};

總結
限制類的對象數量是一種重要的設計模式,用于控制資源使用和確保系統約束。實現時需考慮實例計數、線程安全、生命周期管理和拷貝控制。

關鍵實現技術包括:靜態計數、私有構造函數、刪除拷貝和移動操作、智能指針管理,以及線程同步機制。根據需求選擇單例模式或有限實例模式,并確保設計的一致性和安全性。

在現代C++中,利用RAII、智能指針和線程安全原語可以構建健壯的對象數量限制機制,從而提升代碼的可靠性和可維護性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/97821.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/97821.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/97821.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CMS系統維護中常見的安全威脅及防護指南!

內容管理系統&#xff08;CMS&#xff09;已成為網站建設的核心工具&#xff0c;但隨之而來的安全風險卻常被低估。超過70%的網站使用CMS構建&#xff0c;而其中近半數曾遭遇安全漏洞威脅。作為運維人員和開發者&#xff0c;了解這些安全威脅并采取相應防護措施至關重要。 一、…

springboot knife4j 接口文檔入門與實戰

Spring Boot3 Knife4j 項目地址https://gitee.com/supervol/loong-springboot-study&#xff08;記得給個start&#xff0c;感謝&#xff09;Knife4j 介紹在國內 Java 開發領域&#xff0c;Knife4j 是一款廣受歡迎的 API 文檔工具&#xff0c;它基于 OpenAPI 規范&#xff0c;在…

Spring Boot 事務失效的八大原因及解決方案詳解

在 Spring Boot 項目開發中&#xff0c;聲明式事務管理通過 Transactional 注解提供了極大的便利。但許多開發者都曾遇到過事務不生效的困擾。本文將詳細分析導致 Spring Boot 事務失效的八大常見情況&#xff0c;并提供相應的解決方案。1. 數據庫引擎不支持事務問題分析&#…

數據結構:順序棧與鏈棧的原理、實現及應用

數據結構詳解&#xff1a;順序棧與鏈棧的原理、實現及應用 1. 引言&#xff1a;棧的核心概念 棧&#xff08;Stack&#xff09;是一種重要的線性數據結構&#xff0c;它遵循后進先出&#xff08;Last In First Out, LIFO&#xff09;的原則。這意味著最后一個被添加到棧中的元素…

apipost 8.x 腳本循環調用接口

apipost 8.x 腳本循環調用接口背景實現先說整體邏輯&#xff1a;最后背景 上周為了找某OA 偶爾出現的詭異現象&#xff0c;需要用測試工具來壓測&#xff0c;看看這個問題能否重現。以前用過Jmeter&#xff0c;但是沒有裝&#xff0c;正好有個國產的apipost看看如何&#xff1…

STM32 - Embedded IDE - GCC - 使用 GCC 鏈接腳本限制 Flash 區域

導言如上所示&#xff0c;Keil限制flash區域只需要在IROM1里將Start框框與Size框框填入具體信息即可。比如bootloader程序一般從0x8000000開始&#xff0c;大小0x10000&#xff08;64KB&#xff09;。此時&#xff0c;flash的范圍被限制在0x8000000 ~ 0x800FFFF。 另外&#xf…

Jenkins和Fastlane的原理、優缺點、用法、如何選擇

Jenkins 和 Fastlane 是軟件開發中用于自動化流程的工具一、Jenkins實現自動化打包1.1具體實現步驟安裝與配置&#xff1a;首先在服務器上安裝 Jenkins&#xff0c;可以通過官方提供的安裝包進行安裝&#xff0c;支持多種操作系統。安裝完成后&#xff0c;通過 Web 界面進行初始…

DOM常見的操作有哪些?

1.DOM文檔對象模型&#xff08;DOM&#xff09;是HTML和XML文檔的編程接口它提供了對文檔結構化表述&#xff0c;并定義了一種方式可以使從程序中對該結構進行訪問&#xff0c;從而改變文檔的結構&#xff0c;樣式和內容任何HTML或XML文檔都可以用DOM表示一個由節點構成的層級結…

【Kubernetes】知識點3

25. 說明Job與CronJob的功能。答&#xff1a;Job&#xff1a;一次性作業&#xff0c;處理短暫的一次性任務&#xff0c;僅執行一次&#xff0c;并保證處理的一個或者多個 Pod 成功結束。CronJob&#xff1a;周期性作業&#xff0c;可以指定每過多少周期執行一次任務。26. Kuber…

LINUX-網絡編程-TCP-UDP

1.目的&#xff1a;不同主機&#xff0c;進程間通信。2.解決的問題1&#xff09;主機與主機之間物理層面必須互相聯通。2&#xff09;進程與進程在軟件層面必須互通。IP地址&#xff1a;計算機的軟件地址&#xff0c;用來標識計算機設備MAC地址&#xff1a;計算機的硬件地址&am…

目標檢測定位損失函數:Smooth L1 loss 、IOU loss及其變體

Smooth L1 Loss 概述 Smooth L1 Loss&#xff08;平滑 L1 損失&#xff09;&#xff0c;是一個在回歸任務&#xff0c;特別是計算機視覺中的目標檢測領域&#xff08;如 Faster R-CNN, SSD&#xff09;非常核心的損失函數。 xxx 表示模型的預測值&#xff0c;yyy 表示真實值&am…

Android開發之fileprovider配置路徑path詳細說明

第一步在清單文件配置fileprovider屬性<providerandroid:name"androidx.core.content.FileProvider"android:authorities"${applicationId}.fileprovider"android:exported"false"android:grantUriPermissions"true"><meta-d…

【ComfyUI】圖像描述詞潤色總結

在 ComfyUI 的工作流中&#xff0c;圖像反推描述詞能幫我們從圖像里抽取語義信息&#xff0c;但這些原始描述往往還顯得生硬&#xff0c;缺乏創意或流暢性。為了讓提示詞更自然、更有表現力&#xff0c;就需要“潤色”環節。潤色節點的任務&#xff0c;不是重新生成描述&#x…

java面試中經常會問到的IO、NIO問題有哪些(基礎版)

文章目錄一、IO 基礎與分類二、NIO 核心組件與原理三、NIO 與 BIO 的實戰對比四、AIO 與 NIO 的區別五、Netty 相關&#xff08;NIO 的高級應用&#xff09;總結Java 中的 IO&#xff08;輸入輸出&#xff09;和 NIO&#xff08;非阻塞 IO&#xff09;是面試中的重要考點&#…

時序數據庫選型指南:如何為工業場景挑選最強“數據底座”

工業4.0時代&#xff0c;工廠化身為巨大的數據生產中心。數以萬計的傳感器、PLC和設備每時每刻都在產生著海量的時間序列數據&#xff08;Time-Series Data&#xff09;&#xff1a;溫度、壓力、流速、振動、設備狀態……這些帶時間戳的數據是工業互聯網的血液&#xff0c;蘊含…

【排序算法】冒泡 選排 插排 快排 歸并

一、冒泡排序// 冒泡排序var bubbleSort function (arr) {const len arr.length;for (let i 0; i < len; i) {let isSwap false;for (let j 0; j < len - 1; j) {// 每一次遍歷都要比較相鄰元素的大小&#xff0c;如果滿足條件就交換位置if (arr[j] > arr[j 1])…

電子病歷空缺句的語言學特征描述與自動分類探析(以GPT-5為例)(中)

語言學特征刻畫(特征庫) 句法特征 句法特征是識別 SYN 類電子病歷空缺句的核心語言學維度,其量化分析通過構建依存句法結構的形式化指標,實現對語法不完整性的客觀描述。該類特征主要包括依存樹不完備指標、謂詞-論元覆蓋率及從屬連詞未閉合三類核心參數,共同構成 SYN 類…

InnoDB存儲引擎-事務

1. 事務概述事務可由一條簡單的SQL語句組成,也可以由一組復雜的SQL語句組成. 事務是訪問并更新數據庫中各種數據項的一個程序執行單元. 在事務中的操作, 要么都做修改, 要么都不做. 對于 InnoDB存儲引擎而言, 其默認的事務隔離級別 RR , 完全遵循和滿足了事務的 ACID 特性. 1.1…

web項目的目錄結構

web項目的目錄結構 WEB-INF 存放class文件、jar文件和配置文件&#xff0c;對于用戶來說該文件夾是不可見的WEB-INF/web.xml web應用程序的描述文件&#xff0c;用來配置資源&#xff0c;如servlet、過濾器、監聽器等WEB-INF/classes 用于存放class文件&#xff0c;也是該web應…

數據結構_隊列Queue(C語言實現)

一、隊列的基本概念 1.隊列定義 隊列是一種先進先出的線性表數據結構&#xff08;First in First out&#xff09;,現實中的例子就是&#xff0c;排隊購票&#xff0c;先排隊的先購票&#xff0c;購完票之后直接從這個隊中離開&#xff0c;后來的在這個隊后面排隊&#xff0c;這…