В моем проекте экземпляры некоторых классов создаются более одного раза. Каждый класс регистрирует некоторые события. Метод ведения журнала является общим, который используется во всем проекте, и в нем используется стандартный cout. Сообщение журнала содержит время, имя класса, имя метода, значение переменной и настраиваемое сообщение.
Недостатком является то, что журнал не привязан к конкретному экземпляру. Я не знаю, какой экземпляр класса написал журнал.
Есть ли хороший способ решить эту проблему без добавления дополнительных статических членов в качестве счетчиков экземпляров в классы? Я использую boost и C++ 11. Может быть, у boost есть что-то, что может помочь.
Единственное решение, которое я могу придумать, - это включить адрес экземпляра (this) в журнал.
Итак, вы хотите различать объекты одного класса. В чем заключается отличительная черта и почему он не является (нестатическим) членом класса?
Поможет ли вам просто распечатать адрес экземпляра? Таким образом вы можете сказать, что два экземпляра, пишущие одну и ту же строку, разные.





Более простой способ решить проблему - распечатать адрес, чтобы указать, какой это объект. Как следующее:
cout<<static_cast<void*>(this)<<endl;
Или вывести какие-то особенности.
Обычно у меня есть защищенный член класса, содержащий время создания экземпляра в корне всех моих иерархий классов, по крайней мере, на этапе отладки. Также очень полезно для многопоточных приложений.
Преобразуйте это время во все, что захотите - строку, миллисекунды, время эпохи - и у вас будет уникальный идентификатор для каждого экземпляра.
Вам нужно будет различать разные классы где-то, это несколько вариантов (все зависят от какого-то идентификатора):
this, как вы предложили: this и хешировать значение:Честно говоря, я не вижу большой разницы в 2), но это может вызвать некоторые дальнейшие идеи. Какой-то уродливый взлом может выглядеть так:
#include <iostream>
#include <functional>
#include <cstddef>
class Logger
{
public:
static void log(void* ptr)
{
using hash_type = std::uintptr_t;
std::cout << std::hash<hash_type>{}(reinterpret_cast<hash_type>(ptr))
<< " logged something..." << std::endl;
}
};
Вы также можете рассмотреть специализирующийся на std::hash для своих классов и использовать его в выходных данных журнала. Это устранит проблему изменения адресов между разными запусками, если будет реализовано должным образом.
Заключение: Я бы выбрал вариант 1), если удобочитаемость для людей вызывает беспокойство, и 2), если вам просто нужно какое-то число, чтобы различать сообщения журнала (например, для конвейера и фильтрации).
Если будет всего несколько экземпляров класса, я бы посоветовал вам ввести строковый член и инициализировать его уникальным именем во время создания объекта. Это поможет вам при чтении логов. По умолчанию он может быть инициализирован адресом объекта.
Вы вполне можете без труда генерировать идентификаторы через адаптер CRTP (если вы можете немного изменить свои классы)
template<typename T>
struct enable_id
{
int id = global_id++;
private:
static int global_id;
};
template<typename T>
int enable_id<T>::global_id = 0;
class foo : public enable_id<foo>
{
};
template<typename T>
void log(const T& t)
{
// if is_base_of
std::cout << t.id << std::endl;
}
Как вы сказали, «это» помогает различать экземпляры, но если вы хотите точно знать, какой экземпляр что делает (особенно между разными запусками программы), вам придется как-то называть их во время создания (-> больше членов ).