商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > c++中单例模式使用及说明(局部静态变量)

c++中单例模式使用及说明(局部静态变量)

  发布于2026-05-25 阅读(0)

扫一扫,手机访问

单例模式的作用

聊到单例模式,很多开发者第一反应就是“全局唯一”。没错,它的核心使命正在于此:确保一个类在整个系统生命周期里,有且仅有一个实例,并为所有需要它的代码提供一个统一的访问入口。

它是怎么做到的呢?关键在于私有化构造函数。这样一来,外部代码就无法通过new随意创建对象了。想用?只能通过它提供的那个静态方法去获取。这个方法会负责创建(如果尚未创建)并返回那个唯一的实例。

这么设计的好处显而易见。首先,它解决了资源浪费的问题。想象一下数据库连接池、全局配置管理器这类重量级对象,如果各处都能随意创建,内存和连接资源很快就会被耗尽。单例模式确保了它们只被初始化一次。其次,它极大地简化了对象访问。你不再需要将一个对象像“击鼓传花”一样在十几个模块间手动传递,无论身在代码的哪个角落,直接通过那个全局访问点获取就行,代码瞬间清爽不少。

可以说,单例模式将对象的生命周期管理和访问方式都标准化了,让开发者能更专注于业务逻辑本身。但话又说回来,任何强大的工具都有其双刃性。单例模式如果滥用,会引入隐式的全局状态耦合,让单元测试变得异常困难,代码的模块化和可维护性也会大打折扣。因此,它的使用必须克制,严格限定在那些真正需要“唯一性”的场景。

核心要点:

  • 单例模式通过严格控制实例数量和提供统一入口,实现了资源的集约管理和代码结构的简化。
  • 需要警惕多线程环境下的安全性、以及由此带来的测试复杂度等问题,切忌盲目使用。

单例模式(局部静态变量模式)

//静态局部变量方式实现单例模式
#include
using namespace std;
class S {
private:
	S() {}
	S(const S&) = delete;
	S& operator=(const S&) = delete;
public:
	static S& getS() {
		static S s;
		return s;
	}
};

单例模式的应用(局部静态变量)

#include 
#include 
#include 

/**
 * 配置管理器单例类
 * 在大型项目中,通常需要一个全局唯一的配置中心来管理各种服务配置项
 * 如数据库连接信息、API密钥、服务器端口等
 */
class ConfigManager {
private:
    // 私有构造函数,防止外部直接创建实例
    ConfigManager() {
        // 在构造函数中加载默认配置
        loadDefaultConfig();
        std::cout << "ConfigManager 初始化完成,加载默认配置" << std::endl;
    }

    // 删除拷贝构造函数和赋值操作符,确保单例的唯一性
    ConfigManager(const ConfigManager&) = delete;
    ConfigManager& operator=(const ConfigManager&) = delete;

    // 加载默认配置的方法
    void loadDefaultConfig() {
        configMap["database_host"] = "localhost";
        configMap["database_port"] = "3306";
        configMap["redis_host"] = "localhost";
        configMap["redis_port"] = "6379";
        configMap["api_timeout"] = "5000"; // 毫秒
        configMap["max_connections"] = "100";
    }

    // 存储配置项的哈希表
    std::unordered_map configMap;

public:
    /**
     * 获取单例实例的静态方法
     * C++11 标准保证 static 局部变量的初始化是线程安全的
     */
    static ConfigManager& getInstance() {
        static ConfigManager instance; // 静态局部变量,延迟初始化
        return instance;
    }

    /**
     * 获取配置值
     * @param key 配置项键名
     * @return 配置项对应的值,如果不存在则返回空字符串
     */
    std::string getConfig(const std::string& key) const {
        auto it = configMap.find(key);
        //std::map::iterator it = configMap.find(key);//传统写法
        if (it != configMap.end()) {
            return it->second;
        }
        std::cout << "警告: 未找到配置项 '" << key << "'" << std::endl;
        return "";
    }

    /**
     * 设置配置值
     * 在实际项目中,这个方法可能用于动态更新配置
     * @param key 配置项键名
     * @param value 配置项值
     */
    void setConfig(const std::string& key, const std::string& value) {
        configMap[key] = value;
        std::cout << "配置项 '" << key << "' 更新为: " << value << std::endl;
    }

    /**
     * 打印所有配置项(用于调试)
     */
    void printAllConfigs() const {
        std::cout << "n=== 当前所有配置 ===" << std::endl;
        for (const auto& pair : configMap) {
            std::cout << pair.first << " = " << pair.second << std::endl;
        }
        std::cout << "==================n" << std::endl;
    }
};

/**
 * 模拟数据库连接类
 * 使用配置管理器获取数据库连接参数
 */
class DatabaseConnection {
public:
    DatabaseConnection() {
        // 从配置管理器获取数据库连接参数
        auto& config = ConfigManager::getInstance();
        host = config.getConfig("database_host");
        port = config.getConfig("database_port");

        std::cout << "正在连接数据库: " << host << ":" << port << std::endl;
    }

private:
    std::string host;
    std::string port;
};

/**
 * 模拟 Redis 连接类
 * 同样使用配置管理器获取 Redis 连接参数
 */
class RedisConnection {
public:
    RedisConnection() {
        // 从配置管理器获取 Redis 连接参数
        auto& config = ConfigManager::getInstance();
        host = config.getConfig("redis_host");
        port = config.getConfig("redis_port");

        std::cout << "正在连接 Redis: " << host << ":" << port << std::endl;
    }

private:
    std::string host;
    std::string port;
};

int main() {
    std::cout << "=== 大厂项目配置管理器演示 ===" << std::endl;

    // 场景1: 数据库连接器获取配置
    std::cout << "n--- 初始化数据库连接 ---" << std::endl;
    DatabaseConnection dbConn;

    // 场景2: Redis连接器获取配置
    std::cout << "n--- 初始化Redis连接 ---" << std::endl;
    RedisConnection redisConn;

    // 场景3: 验证单例的唯一性
    std::cout << "n--- 验证单例模式 ---" << std::endl;
    auto& config1 = ConfigManager::getInstance();
    auto& config2 = ConfigManager::getInstance();

    if (&config1 == &config2) {
        std::cout << "验证成功: 两次获取的实例是同一个对象" << std::endl;
    }
    else {
        std::cout << "验证失败: 获取到了不同的实例" << std::endl;
    }

    // 场景4: 动态修改配置
    std::cout << "n--- 动态修改配置 ---" << std::endl;
    auto& config = ConfigManager::getInstance();
    config.setConfig("database_host", "prod-database.company.com");
    config.setConfig("api_timeout", "10000");

    // 验证配置是否更新
    std::cout << "更新后的数据库主机: " << config.getConfig("database_host") << std::endl;
    std::cout << "更新后的API超时时间: " << config.getConfig("api_timeout") << "ms" << std::endl;

    // 场景5: 打印所有配置
    config.printAllConfigs();

    // 场景6: 模拟新连接使用更新后的配置
    std::cout << "n--- 新连接使用更新后的配置 ---" << std::endl;
    DatabaseConnection newDbConn; // 这个连接会使用更新后的主机地址

    return 0;
}

运行结果

c++中单例模式使用及说明(局部静态变量)

总结

通过上面的原理阐述和完整示例,我们可以清晰地看到,使用局部静态变量是实现C++单例模式一种非常简洁、安全(C++11后线程安全)的方式。它将“唯一实例”与“便捷访问”的特性结合得恰到好处,特别适合管理全局唯一的资源或服务。当然,在实际项目中,仍需根据具体场景权衡其利弊,确保设计模式的引入真正服务于代码质量的提升。

本文转载于:https://www.jb51.net/program/364412kpq.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注