You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

常量结构的设计模式:如何确保初始化后字段不可修改?

确保配置结构体初始化后不可修改的惯用做法

针对你提到的场景,有几种C++里的惯用方案可以保证配置结构体初始化后不被修改,同时避开直接使用带const字段的结构体:

方案一:返回值+客户端const接收

这是最简单直接的方式,函数按值返回普通结构体,要求客户端用const变量接收,从编译层面阻止修改。

#include <string>

struct Config {
    int timeout;
    std::string endpoint;
};

// 加载配置的函数
Config load_config(const std::string& config_path) {
    Config cfg;
    // 模拟从文件读取配置的逻辑
    cfg.timeout = 30;
    cfg.endpoint = "http://api.example.com";
    return cfg;
}

// 客户端使用示例
int main() {
    const Config app_cfg = load_config("config.ini");
    // app_cfg.timeout = 60; // 编译报错:无法修改const对象的成员
    return 0;
}

这种方式的核心是依赖客户端遵守const接收的约定——虽然客户端理论上可以用非const变量接收后修改,但这属于主动破坏不可变性的设计意图,在团队开发中可以通过编码规范约束,大多数场景下足够实用。

方案二:封装为不可变类(强制不可修改)

如果需要彻底从代码层面阻止修改,可以把结构体封装成类,将字段私有化,只提供只读访问器,同时禁用赋值操作,通过静态工厂函数创建实例。

#include <string>

class Config {
public:
    // 静态工厂函数:负责加载配置并创建实例
    static const Config load(const std::string& config_path) {
        Config cfg;
        // 模拟读取配置
        cfg.timeout_ = 30;
        cfg.endpoint_ = "http://api.example.com";
        return cfg;
    }

    // 只读访问器
    int timeout() const { return timeout_; }
    const std::string& endpoint() const { return endpoint_; }

    // 禁用赋值操作,避免被修改
    Config& operator=(const Config&) = delete;

private:
    // 私有构造函数:只能通过工厂函数创建实例
    Config() = default;
    
    // 私有字段:外部无法直接访问
    int timeout_;
    std::string endpoint_;
};

// 客户端使用示例
int main() {
    const Config app_cfg = Config::load("config.ini");
    // app_cfg.timeout_ = 60; // 编译报错:私有成员不可访问
    // app_cfg = Config::load("other.ini"); // 编译报错:赋值操作被禁用
    return 0;
}

这种方案完全杜绝了外部修改的可能,代价是需要编写访问器函数,适合对配置不可变性要求极高的场景。

方案三:返回const引用(避免拷贝)

如果配置结构体较大,不想返回值拷贝,可以返回const引用,但要注意对象的生命周期。通常可以用静态存储的实例,保证在程序运行期间有效:

#include <string>
#include <mutex>

struct Config {
    int timeout;
    std::string endpoint;
};

std::mutex config_mutex;

const Config& load_config(const std::string& config_path) {
    static Config cfg;
    static bool is_loaded = false;

    std::lock_guard<std::mutex> lock(config_mutex);
    if (!is_loaded) {
        // 模拟读取配置
        cfg.timeout = 30;
        cfg.endpoint = "http://api.example.com";
        is_loaded = true;
    }
    return cfg;
}

// 客户端使用示例
int main() {
    const Config& app_cfg = load_config("config.ini");
    // app_cfg.timeout = 60; // 编译报错:无法修改const引用的对象
    return 0;
}

这种方式避免了拷贝开销,但要注意线程安全(初始化时加锁),且配置只能加载一次,不支持动态重新加载的场景。


内容的提问来源于stack exchange,提问作者Oodini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:18:27