You need to enable JavaScript to run this app. 如何在C++类方法中声明不被所有实例共享的持久化局部变量?
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++类方法中声明不被所有实例共享的持久化局部变量?

问题解决方案

基础场景(实例独立的函数内持久变量)

你原来的代码达不到预期,是因为函数内部的static变量属于函数本身,所有类实例共享,生命周期和程序一致,不会随实例变化。
要同时满足「仅函数内可见」「多次调用值持久」「每个实例独立」三个要求,可以用静态实例映射表的方案实现,修改后的代码如下:

#include <unordered_map>
class A {
   void foo() {
      // 仅当前函数可见的静态映射表,key为实例指针,value为对应实例的i值
      static std::unordered_map<A*, int> instance_i_map;
      // 取出当前实例对应的i变量,不存在则默认初始化为0
      int& i = instance_i_map[this];
      std::cout << i << std::endl;
      i++;
   }
};

// 测试代码
auto i1 = A();
auto i2 = A();
i1.foo(); // 输出0
i2.foo(); // 输出0
i1.foo(); // 输出1
i2.foo(); // 输出1

日志限流宏修改方案

你原来的宏用了内部静态变量next_log_time,所以所有类实例会共享同一个限流时间,只要把静态变量换成基于this指针的映射表即可实现实例独立的限流逻辑,修改后的宏如下:

#include <unordered_map>
// 可选:多线程环境需要引入mutex头文件加锁
// #include <mutex>

#define ROS_UTILS_THROTTLE_MACRO(LOG_MACRO, message, duration) do {                                         \
  /* 按行号生成唯一静态映射表,存储每个实例对应的下一次日志时间 */                                            \
  static std::unordered_map<void*, rclcpp::Time> COMBINE(throttle_next_time_,__LINE__);                      \
  /* 多线程场景请打开下方两行注释,避免并发访问map出错 */                                                    \
  // static std::mutex COMBINE(throttle_mutex_,__LINE__);                                                    \
  // std::lock_guard<std::mutex> lock(COMBINE(throttle_mutex_,__LINE__));                                    \
  auto& next_log_time = COMBINE(throttle_next_time_,__LINE__)[this];                                         \
  const auto current_time = ros2_utils::system_time_now();                                                   \
  /* 首次调用初始化下一次日志时间 */                                                                         \
  if (next_log_time == rclcpp::Time(0)) {                                                                    \
    next_log_time = current_time + duration;                                                                 \
  }                                                                                                          \
  if(current_time >= next_log_time)                                                                          \
  {                                                                                                          \
      LOG_MACRO(message);                                                                                    \
      next_log_time += duration;                                                                             \
      /* 避免长时间没调用后首次触发需要等多次周期的问题 */                                                    \
      if(next_log_time <= current_time)                                                                      \
      {                                                                                                      \
          next_log_time = current_time + duration;                                                           \
      }                                                                                                      \
  }                                                                                                          \
} while (0)

修改说明

  1. 移除了原来的静态lambda和内部静态时间变量,改用this指针作为key的映射表存储每个实例的限流时间,完全隔离不同实例的限流逻辑
  2. 按行号生成独立的映射表,同一个函数内多处调用宏也不会互相干扰,和原宏的设计逻辑兼容
  3. 新增了首次调用的时间初始化逻辑,符合限流的预期行为

注意事项

如果你的业务有大量实例频繁创建销毁,映射表会残留已经销毁实例的无效key,可以根据实际场景补充清理逻辑,或者把key换成std::weak_ptr(前提是类实例用std::shared_ptr管理)避免无效内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 05:54:04