Вот один из подходов, использующий stati c контейнер указателей экземпляров.
Следует иметь в виду, что каждая конструкция / разрушение input_shift_reg
будет иметь побочные эффекты, а именно обновление s_instances
контейнер. То есть, если ваш существующий код копирует их, передавая их по значению в функции, у вас будет много обновлений для instances
deque.
Еще одна потенциальная проблема, о которой следует быть осторожным, - это ошибка, подобная повторному входу, если вы создаете / уничтожаете input_shift_reg
объекты, перебирая контейнер экземпляров.
template <typename T>
class tracked
{
static std::deque<T*> s_instances;
public:
static const std::deque<T*>& instances() { return s_instances; }
static std::size_t number_instances() { return s_instances.size(); }
protected:
tracked()
{
s_instances.push_back(this);
}
~tracked() noexcept()
{
auto it = std::find(s_instances.begin(), s_instances.end(), this);
assert(it != s_instances.end());
s_instances.erase(it);
}
};
class input_shift_reg : public tracked<input_shift_reg> {
/* ... */
};
void inputShiftSnapShot()
{
// Perform snapshot.
PORTD &= ~(1 << loadPin);
delay(1);
PORTD ^= (1 << loadPin);
for (input_shift_reg* reg : tracked<input_shift_reg>::instances())
{
// Use `reg` to update instance.
reg->set_data(...);
}
}
Если вы не хотите усложнять stati c членов, вы можете сделать deque of pointers обычной переменной-членом и заставить вызывающих создать input_shift_reg
, вызывая некоторую функцию create(...)
в объекте, похожем на пул. В этом случае вы захотите сделать объекты не копируемыми и неподвижными, чтобы пул не выходил из синхронизации c с объектами.