【问题标题】:C++ object lifetime profilingC++ 对象生命周期分析
【发布时间】:2013-02-24 10:03:30
【问题描述】:

ObjectInfo 类是一个诊断类,用于跟踪统计数据,例如生命周期和对象数量。如图所示,一个特定的类继承自 ObjectInfo。然后在分析类的主体中声明该特定类的成员。

虽然该解决方案有效,但很难维护,因为它要求分析类与分析类保持同步,因为类名用于标识后者。也很难扩展分析类来收集不同的信息,例如对象的大小。

提出一个更好的解决方案,其中分析类和分析类之间的依赖关系最小。

是否有可能实现一个检查来确定所分析类的对象是在堆栈还是堆上创建的?

-- ObjectInfo.h--

#pragma once

class ObjectInfo
{
 public:
  ObjectInfo(const char* objectName);
  virtual ~ObjectInfo(void);

 private:

   static int  m_counter;
   int         m_objectNumber;
   const char* m_className;
};

-- ObjectInfo.cpp--

#include "StdAfx.h"
#include "ObjectInfo.h"
#include <iostream>
#include "TimePrinter.h"

using namespace std;
int ObjectInfo::m_counter = 0;
ObjectInfo::ObjectInfo(const char* name) :
m_className(name)
{
   m_objectNumber = ++m_counter;
   cout << "Object: " << m_className << "# " << m_objectNumber << " created @ " <<
   TimePrinter()<< endl;
}

ObjectInfo::~ObjectInfo(void)
{
  cout << "Object: " << m_className << "# " << m_objectNumber << " destroyed @ " << 
  TimePrinter() << endl;
}

-- 使用模式--

struct _AInfo : public ObjectInfo {
    _AInfo() : ObjectInfo("_A") {}
};

struct _A {
  _AInfo m_info;
};

我原本以为这个问题是在询问使用 C++ 反射技术来收集运行时信息。但是,我不知道是否有一种方法可以使用 C++ 反射来测量对象的生命周期。此外,您能否认为 C++ 反射是一种减少分析类和分析类之间依赖关系的技术?

【问题讨论】:

  • 我认为您可以将ObjectInfo 设为模板并直接从其继承:class A : public ObjectInfo&lt;A&gt;
  • @BartekBanachewicz:这就是所谓的 CRTP,即奇怪重复的模板模式。
  • 知道我以前偶然发现过这个:P
  • 奇怪的重复模板模式!这很好奇!谢谢

标签: c++ design-patterns rtti


【解决方案1】:

这可以跟踪堆栈与堆对象的创建

#include <iostream>

template <class CRTP>
struct AllocationTracker
{
    AllocationTracker()
    {
        ++totalCreated;
    }

    void* operator new(size_t sz)
    {
        ++heapCreated;
        return ::operator new(sz);
    }

    static int totalCreated;
    static int heapCreated;
};

template <class CRTP>
int AllocationTracker<CRTP>::totalCreated;
template <class CRTP>
int AllocationTracker<CRTP>::heapCreated;

class Derived : public AllocationTracker<Derived>
{
};

int main()
{
    using namespace std;
    cout << Derived::heapCreated << "/" << Derived::totalCreated << endl; // 0/0
    Derived dStack;
    cout << Derived::heapCreated << "/" << Derived::totalCreated << endl; // 0/1
    Derived* dHeap = new Derived;
    cout << Derived::heapCreated << "/" << Derived::totalCreated << endl; // 1/2
}

这使用了 Bartek 在您的问题的 cmets 中提出的 CRTP。这让我们可以分别跟踪每个派生类型。它还包装了基类的标准new,它由派生类继承,这允许我们跟踪堆分配。所以我们知道有多少实例被创建,有多少在堆上,我们可以推断其余的都在堆栈上(除非你在程序中使用对象池或其他一些更奇特的分配策略)。

【讨论】:

  • 在这种情况下你如何处理类名?你还把类名作为字符串传递吗?
  • 我没有任何书籍推荐,但我确信 Amazon.com 有。至于类名,你可以将它作为字符串传递给我的解决方案,或者你可以考虑简单地使用typeid(CRTP).name() 来自动获取它(尽管使用特定于平台的格式)。
  • 当我再次思考这个问题时:“是否可以确定对象是在堆栈还是堆上创建的?”,我认为答案非常有趣。在多线程环境中考虑这个问题,同时创建两个对象。堆上只创建了一个,你能确定堆上是哪一个吗?
  • 当然。在自定义运算符 new 中,只需在返回之前记录每个地址。使用 std::set 或其他东西。然后,当您想知道特定对象是否在堆上时,只需检查this 是否在堆分配地址集中。我想你也应该在删除时从集合中删除。
  • 哇,非常感谢。对不起,我没有足够的投票声望。您的回答值得赞赏。
猜你喜欢
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
相关资源
最近更新 更多