适配不可拷贝移动timer类的C++标准库容器选型咨询
问题背景与需求
我基于FreeRTOS定时器API封装了一个C++类,该类静态分配由后台FreeRTOS线程操作的定时器控制块。如果移动或拷贝该对象,控制块会随之移动/拷贝,但后台线程无法感知,因此我将该类设为不可拷贝且不可移动。
类的框架如下:
#include <cstdint> #include <concepts> template <std::invocable Cb> class timer { public: timer() = default; timer(Cb cb, TickType_t timer_period, bool auto_reload = false) : cb_{ cb } { xTimerCreateStatic("timer", timer_period, auto_reload, static_cast<void*>(this), &timer::timer_expired_cb, &buf_); } timer(const timer&) = delete; timer(timer&&) = delete; auto operator=(const timer&) = delete; auto operator=(timer&&) = delete; // ... private: Cb cb_; TimerHandle_t handle_; StaticTimer_t buf_; };
现在我想将多个此类timer对象存入可动态扩展或收缩的C++标准库容器,是否存在无需对象可移动或可拷贝的符合要求的容器?
解决方案
有两种可行的方案,不需要修改timer类的不可拷贝/不可移动特性:
1. 存储智能指针的标准容器
所有支持动态扩展的C++标准容器(比如std::vector、std::list、std::deque)都可以存储智能指针,推荐用std::unique_ptr<timer<Cb>>(独占所有权)或std::shared_ptr<timer<Cb>>(共享所有权):
- 智能指针本身支持移动(
std::unique_ptr)或拷贝+移动(std::shared_ptr),容器扩展时只会操作指针,不会触碰底层的timer对象,完全规避了拷贝/移动timer实例的风险。 - 示例代码:
// 定义存储unique_ptr的vector std::vector<std::unique_ptr<timer<MyCallbackFunc>>> timer_list; // 原地创建timer并加入容器 timer_list.emplace_back(std::make_unique<timer<MyCallbackFunc>>( [](){ /* 定时器回调逻辑 */ }, pdMS_TO_TICKS(1000), true ));
2. 使用std::vector<std::optional<timer<Cb>>>(C++17+)
如果希望直接存储对象而非指针,可以用std::optional包装timer后存入std::vector:
std::optional允许容器中存在空位置,你可以通过emplace在容器的空位置原地构造timer对象,全程不会触发timer的拷贝或移动操作。- 示例代码:
std::vector<std::optional<timer<MyCallbackFunc>>> timer_list; // 预分配容器空间 timer_list.resize(3); // 在指定位置原地构造timer timer_list[0].emplace( [](){ /* 回调逻辑 */ }, pdMS_TO_TICKS(500), false ); // 直接追加一个构造好的optional对象 timer_list.emplace_back(std::in_place, [](){}, pdMS_TO_TICKS(2000), true);
关键注意点
- 无论采用哪种方案,都要保证
timer对象的生命周期不短于后台FreeRTOS线程的生命周期,避免出现悬垂引用或无效定时器控制块。 - 务必在
timer类的析构函数中调用xTimerDelete清理FreeRTOS定时器资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

