跟踪(堆栈分配的)对象

时间:2016-12-08 08:49:29

标签: c++ pointers reference global

在一个相当大的应用程序中,我想跟踪某些类的对象的一些统计信息。为了不降低性能,我希望在拉配置中更新统计数据。因此,我需要在某个位置引用每个活动对象。是否有惯用方式:

  1. 创建,搜索,迭代此类参考
  2. 自动管理(即在销毁时删除参考)
  3. 我在考虑一组智能指针,但是内存管理会有些颠倒:当智能指针被销毁时,我不想破坏智能指针,而是对象被破坏了。理想情况下,我不想重新发明轮子。

    我可以延迟删除指针,我只需要一种方法来快速使它们失效。

    编辑:因为稻田要求它:基于拉动的收集的原因是获取信息可能相对昂贵。推动显然是一个干净的解决方案,但被认为太昂贵了。

2 个答案:

答案 0 :(得分:2)

该语言没有特殊功能可以让您这样做。有时对象跟踪是通过滚动自己的内存分配器来处理的,但这在堆栈上并不容易。

但是,如果你只使用堆栈,它实际上会让你的问题更容易,假设被跟踪的对象在一个线程上。 C ++对栈的构造和破坏顺序提供了特殊的保证。也就是说,销毁订单正好与施工订单相反。

因此,您可以利用它在每个对象中存储单个指针,以及一个跟踪最新对象的静态指针。现在,您有一个表示为链表的对象堆栈。

template <typename T>
class Trackable
{
public:
    Trackable()
    : previous( current() )
    {
        current() = this;
    }

    ~Trackable()
    {
        current() = previous;
    }

    // External interface
    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> {};

//  :::

// Walk linked list of Foo objects currently on stack.
for( Foo *foo = Foo::head(); foo; foo = foo->next() )
{
    // Do kung foo
}

现在,诚然,这是一个非常简单的解决方案。在大型应用程序中,您可能使用对象有多个堆栈。您可以通过使current()使用thread_local语义来处理多个线程上的堆栈。虽然你需要一些魔法来使这项工作,因为head()需要指向一个线程注册表,这需要同步。

您绝对不希望将所有堆栈同步到一个列表中,因为这会破坏您的程序的性能可伸缩性。

至于你的拉动要求,我认为它是一个想要遍历列表的单独线程。您需要一种同步方法,以便在迭代列表时在Trackable<T>内阻止所有新对象构造或销毁。或类似的。

但至少你可以把这个基本想法扩展到你的需要。

请记住,如果动态分配对象,则无法使用此简单列表方法。为此你需要一个双向列表。

答案 1 :(得分:2)

最简单的方法是在每个对象中包含代码,以便它在实例化时自行注册,并在销毁时自行删除。可以使用CRTP轻松注入此代码:

template <class T>
struct AutoRef {

    static auto &all() {
        static std::set<T*> theSet;
        return theSet;
    }

private:
    friend T;

    AutoRef() { all().insert(static_cast<T*>(this)); }
    ~AutoRef() { all().erase(static_cast<T*>(this)); }
};

现在,Foo类可以从AutoRef<Foo>继承,以便在AutoRef<Foo>::all()内引用其实例。

See it live on Coliru