没有特别的语言功能可以让您这样做。有时,对象跟踪是通过自己的内存分配器来处理的,但在堆栈上很难实现。
但是,如果您只使用堆栈,假设被跟踪的对象在单个线程中,它实际上使问题变得更容易了。C++对于堆栈上构造和销毁的顺序做出了特殊保证。也就是说,销毁顺序正好与构造顺序相反。
因此,您可以利用这一点,在每个对象中存储一个指针,加上一个静态指针来跟踪最新的对象。现在,您拥有一个表示为链表的对象堆栈。
template <typename T>
class Trackable
{
public:
Trackable()
: previous( current() )
{
current() = this;
}
~Trackable()
{
current() = previous;
}
static const T *head() const { return dynamic_cast<const T*>( current() ); }
const T *next() const { return dynamic_cast<const T*>( previous ); }
private:
static Trackable * & current()
{
static Trackable *ptr = nullptr;
return ptr;
}
Trackable *previous;
}
例子:
struct Foo : Trackable<Foo> {};
struct Bar : Trackable<Bar> {};
for( Foo *foo = Foo::head(); foo; foo = foo->next() )
{
}
现在,诚然这是一个非常简单的解决方案。在一个大型应用程序中,您可能会有多个堆栈使用您的对象。您可以通过使
current()
使用thread_local语义来处理多个线程上的堆栈。虽然您需要一些魔法才能使其工作,因为
head()
需要指向线程注册表,这将需要同步。
您绝对不希望将所有堆栈同步到单个列表中,因为这将破坏程序的性能可伸缩性。
至于您的拉取要求,我认为这是一个单独的线程想要遍历列表。您需要一种同步方式,以便在迭代列表时阻止所有新对象构造或销毁在
Trackable<T>
内部。或类似的操作。
但至少您可以采用这个基本思路并将其扩展到满足您的需求。
请记住,如果您动态分配对象,则不能使用此简单列表方法。对此,您需要一个双向列表。
Countable
的想法,并将其改为了Trackable
。现在,单个堆栈可以将对象推入到可以作为链表迭代的堆栈结构中。它非常轻量级,可能是你正在寻找的开始。一旦你想要从另一个线程使用它,就会出现同步问题,但我相信你可以处理它=) - paddy