Профилирование времени жизни объекта C++

Класс 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++ методом, который уменьшает зависимости между классами профилирования и профилирования?


person Fantasy    schedule 24.02.2013    source источник
comment
Я думаю, вы могли бы сделать ObjectInfo шаблоном и наследовать от него напрямую: class A : public ObjectInfo<A>.   -  person Bartek Banachewicz    schedule 24.02.2013
comment
@BartekBanachewicz: это называется CRTP, любопытно повторяющийся шаблон шаблона.   -  person John Zwinck    schedule 24.02.2013
comment
Я знал, что натыкался на это раньше :P   -  person Bartek Banachewicz    schedule 24.02.2013
comment
Любопытно повторяющийся шаблон шаблона! Это очень Любопытно! благодарю вас   -  person Fantasy    schedule 24.02.2013


Ответы (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
}

При этом используется CRTP, который Бартек привел в комментариях к вашему вопросу. Это позволяет нам отслеживать каждый производный тип отдельно. Он также является оболочкой стандартного new для базового класса, который наследуется производными классами, что позволяет нам отслеживать выделение кучи. Итак, мы знаем, сколько экземпляров создано и сколько в куче, и можем сделать вывод, что остальные были в стеке (если только вы не используете пулы объектов или какие-то другие более экзотические стратегии распределения в своей программе).

person John Zwinck    schedule 24.02.2013
comment
Как вы относитесь к имени класса в этом случае? Вы по-прежнему передаете имя класса в виде строки? - person Fantasy; 24.02.2013
comment
У меня нет рекомендаций по книгам, хотя я уверен, что они есть на Amazon.com. Что касается имени класса, вы можете добавить свой способ передачи его в виде строки в мое решение, или вы можете просто использовать typeid(CRTP).name() для его автоматического получения (хотя и в формате, специфичном для платформы). - person John Zwinck; 24.02.2013
comment
Когда я еще раз задумался над вопросом: можно ли определить, был ли объект создан в стеке или в куче?, я думаю, что ответ будет очень интригующим. Рассмотрим этот вопрос в многопоточной среде, два объекта создаются одновременно. В куче создается только один, можете ли вы определить, какой из них находится в куче? - person Fantasy; 02.03.2013
comment
Конечно. В пользовательском операторе new просто записывайте каждый адрес перед его возвратом. Используйте std::set или что-то в этом роде. Затем, когда вы хотите узнать, находится ли конкретный объект в куче, просто проверьте, находится ли this в наборе адресов, выделенных в куче. Думаю, вам тоже следует удалить из набора при удалении. - person John Zwinck; 02.03.2013
comment
вау, большое спасибо. Извините, мне не хватило репутации для голосования. Ваш ответ заслуживает уважения. - person Fantasy; 03.03.2013
comment
Я думаю, вы сможете принять мой ответ, нажав на галочку слева от него. - person John Zwinck; 04.03.2013