I built a C++ wrapper around the FreeRTOS timer API. My class statically allocates the timer control block which is operated by a FreeRTOS thread in the background. This means that if I move or copy this object, the control block will be moved/copied as well BUT the thread wont notice that. Because of that I consider the object non-copyable and non-movable.
Here's the outline:
#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_;
};
Now I want to push multiple of this timer objects into a C++ container which I can dynamically extend or shrink as objects enter or leave the container. Is there a stdlib container that doesn't require objects to be moveable or copyable and still provides all the functionality?
I see four basic options:
std::list<timer>
: This might be one of the very rare cases when using std::list
is the best option. Insertion into the list must be done via one of the emplace member functions, as you cannot move in an already existing object.std::vector<std::unique_ptr<timer>>
: In case construction of timer
objects is not directly associated with keeping them in your container. This has the disadvantage that accessing and removing entries slightly more work than std::list
. But your timer
factory doesn't need to know how you plan to store the object.std::set<timer>
: You stated that you have new objects arriving and departing. If you have a lot of them, maybe you want to avoid find
ing them in a linear container. std::set
also has no reallocations and offers you a nice interface for finding and erasing objects. But clearly it has more overhead than the other two suggestions.std::array<std::optional<timer>, N>
: If you know the maximal number N of timers you will see at runtime, consider a fixed-size array with optionals in it. This has no pointer-indirections but you likely have a number of branches when searching an item.