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

如何在变量超出作用域时重置多个变量?

多变量作用域退出时自动重置的实现方案

你已经实现了单变量的栈式自动重置逻辑,现在要扩展到多变量版本,下面针对你的疑问逐一给出实现方案:

原单变量实现代码

template<typename T>
struct Context
{
    T savedValue;
    T& ref;
    Context(T& value) : savedValue(value), ref(value) {}

    ~Context()
    {
        ref = savedValue;
    }
};
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
// __line__ to allow multiple
#define SAVE_CONTEXT(var) Context<decltype(var)> CONCAT(ctx, __LINE__)(var)   

1. 成员变量ref的类型

不能用单一的T&,因为要存储多个不同类型变量的引用,应该使用std::tuple<Ts&...>作为引用容器,这样可以保存任意数量、任意类型的变量引用。

2. 构造函数实现

构造函数需要接收所有待保存变量的引用,同时把每个变量的当前值存入savedValues(std::tuple<Ts...>类型),并把变量引用存入ref成员:

template<typename... Ts>
struct Context
{
    std::tuple<Ts...> savedValues;
    std::tuple<Ts&...> refs;

    // 构造函数:接收变量引用,保存原始值和引用
    Context(Ts&... vars) 
        : savedValues(vars...),  // 拷贝每个变量的当前值到savedValues
          refs(vars...)          // 保存每个变量的引用
    {}

3. 析构函数的重置逻辑

需要遍历tuple的每个元素,将savedValues中保存的原始值赋值给refs中对应的变量引用。利用C++14的std::index_sequence实现编译期遍历:

private:
    // 辅助函数:通过索引序列逐个赋值
    template<std::size_t... Is>
    void reset(std::index_sequence<Is...>)
    {
        // 折叠表达式:对每个索引Is,执行赋值操作
        (std::get<Is>(refs) = std::get<Is>(savedValues), ...);
    }

public:
    ~Context()
    {
        // 生成对应长度的索引序列,调用重置函数
        reset(std::index_sequence_for<Ts...>{});
    }
};

4. 宏定义编写

支持可变参数,同时生成唯一的实例名(避免同作用域内重复定义),模板会自动推导每个变量的类型:

#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
#define SAVE_CONTEXT(...) Context CONCAT(ctx, __LINE__)(__VA_ARGS__)

完整代码与使用示例

#include <tuple>
#include <utility> // 用于std::index_sequence
#include <string>

template<typename... Ts>
struct Context
{
    std::tuple<Ts...> savedValues;
    std::tuple<Ts&...> refs;

    Context(Ts&... vars) 
        : savedValues(vars...),
          refs(vars...)
    {}

private:
    template<std::size_t... Is>
    void reset(std::index_sequence<Is...>)
    {
        (std::get<Is>(refs) = std::get<Is>(savedValues), ...);
    }

public:
    ~Context()
    {
        reset(std::index_sequence_for<Ts...>{});
    }
};

#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
#define SAVE_CONTEXT(...) Context CONCAT(ctx, __LINE__)(__VA_ARGS__)

// 使用示例
int main()
{
    int a = 1;
    double b = 2.5;
    std::string c = "hello";

    {
        SAVE_CONTEXT(a, b, c); // 保存当前值
        a = 100;
        b = 3.14;
        c = "modified";
        // 此处变量已被修改
    }
    // 作用域退出后,a、b、c自动恢复为原始值:1, 2.5, "hello"
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 02:17:21