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

C++共享结构体最佳实践:只读大结构体的传递方式选择

How to Safely Pass a Large Read-Only Struct to Multiple Classes (Avoiding Copies & Raw Pointers)

Hey there! Let's break down your problem step by step—you've got a bulky struct loaded from JSON, need multiple classes to use it in read-only mode without copying the whole thing, and you're wondering whether references or std::shared_ptr is the right call (since raw pointers are off the table). Let's dive into the best options:

1. Preferred: const References (When You Control Lifecycle)

If you can guarantee the struct will outlive all the class objects that use it (e.g., the struct is created early in your program and destroyed only after all dependent classes are gone), a const reference is your best bet. It's zero-overhead, clean, and explicitly signals "read-only" access.

How to implement it:

First, define your struct and load it as const to enforce immutability from the start:

#include <string>
#include <vector>

// Your large struct from JSON
struct ConfigData {
    std::string app_name;
    int max_users;
    std::vector<std::string> allowed_ips;
    // ... lots more fields
};

// Load the JSON into a const struct (so no accidental modifications)
const ConfigData load_config_from_json(const std::string& filename) {
    // ... JSON parsing logic here
    return ConfigData{};
}

Then, pass a const reference to your class constructors, and store a const reference inside the class (or just use the reference directly in methods):

class UserManager {
private:
    const ConfigData& config_; // Store the const reference
public:
    // Constructor takes const reference
    explicit UserManager(const ConfigData& config) : config_(config) {}

    void check_user_limit() const {
        // Read-only access to config_
        if (current_user_count >= config_.max_users) {
            // ... handle limit
        }
    }
};

class IpFilter {
private:
    const ConfigData& config_;
public:
    explicit IpFilter(const ConfigData& config) : config_(config) {}

    bool is_ip_allowed(const std::string& ip) const {
        // Read-only access to config_
        return std::find(config_.allowed_ips.begin(), config_.allowed_ips.end(), ip) != config_.allowed_ips.end();
    }
};

Pros:

  • No overhead (no copy, no reference counting)
  • Clear intent: const makes it impossible to modify the struct accidentally
  • Simple syntax

Cons:

  • You must strictly manage the struct's lifecycle. If the struct is destroyed before the class objects, you'll get a dangling reference (undefined behavior).

2. std::shared_ptr<const ConfigData> (For Uncertain Lifecycles)

If you can't guarantee the struct will outlive all dependent classes, or if you need to share ownership across multiple parts of your program (e.g., some classes might outlive others), use a std::shared_ptr<const ConfigData>. This lets the struct stay alive as long as at least one class holds a pointer to it.

How to implement it:

Load the struct into a shared_ptr<const ConfigData>:

#include <memory>

std::shared_ptr<const ConfigData> load_config_safely(const std::string& filename) {
    // Create the struct as a shared_ptr with const qualifier
    auto config = std::make_shared<ConfigData>();
    // ... parse JSON into *config
    return config; // Implicitly converts to shared_ptr<const ConfigData>
}

Then pass and store the shared_ptr in your classes:

class UserManager {
private:
    std::shared_ptr<const ConfigData> config_;
public:
    explicit UserManager(std::shared_ptr<const ConfigData> config) : config_(std::move(config)) {}

    void check_user_limit() const {
        // Read-only access via config_
        if (current_user_count >= config_->max_users) {
            // ... handle limit
        }
    }
};

class IpFilter {
private:
    std::shared_ptr<const ConfigData> config_;
public:
    explicit IpFilter(std::shared_ptr<const ConfigData> config) : config_(std::move(config)) {}

    bool is_ip_allowed(const std::string& ip) const {
        return std::find(config_->allowed_ips.begin(), config_->allowed_ips.end(), ip) != config_->allowed_ips.end();
    }
};

Pros:

  • Automatic lifecycle management: The struct is destroyed only when the last shared_ptr goes out of scope—no dangling references
  • Still enforces read-only access via const
  • Flexible for complex ownership scenarios

Cons:

  • Minimal overhead from reference counting (negligible compared to copying a large struct)

Which Should You Choose?

  • Go with const references if you have full control over the struct's lifecycle and can ensure it outlives all users. It's the most efficient and clean option.
  • Use std::shared_ptr<const T> if lifecycle is uncertain, or if you need to share ownership across components. It's safer and still avoids copies.

And to address the raw pointer concern: Raw pointers don't convey ownership or immutability clearly, making it easy to accidentally create dangling pointers or modify data you shouldn't. const references and shared_ptr<const T> are far more expressive and align with modern C++ best practices.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:30:28