C ++日志记录类实例标识符

时间:2018-05-24 06:06:07

标签: c++ c++11

在我的项目中,一些类被多次实例化。每个类记录一些事件。日志记录方法是一个在项目周围使用的通用方法,它使用标准的 cout 。日志消息包含时间,类的名称,方法的名称,变量值和自定义消息。

缺点是日志不是特定于实例的。我不知道该类的哪个实例写了日志。

有没有一种很好的方法来解决这个问题,而无需在类中添加额外的静态成员作为实例计数器?我正在使用boost和C ++ 11。也许助推有可能有所帮助。

我能想到的唯一解决方案是将实例地址(this)包含在日志中。

3 个答案:

答案 0 :(得分:1)

您需要区分不同的类某处,这些是一些选项(都依赖于某种ID):

  1. 添加一些额外的静态变量 不是你的选择,但在我看来,如果你的目标是可读性,最好的方法。
  2. 按照您的建议使用this
    这显然会生成唯一的ID,但它们往往难以理解,难以与不断增长的地址长度区分开来(因为冗长的地址字符串中只有一个或两个字符可能不同)。此外,地址可能会在每次运行应用程序之间发生变化(特别是在使用ASLR时),因此您将无法看到哪个确切的实例创建了哪一行输出(如果需要)。
  3. 使用this哈希值
  4. 老实说,我认为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;
        }
    };
    

    您还可以考虑为您的类specializing std::hash并在日志记录输出中使用它。如果实施得当,这将消除在不同运行之间更改地址的问题。

    1. 在构造期间生成ID(例如,通过将一些标识符传递给构造函数):
      这不是一个真正的选择,因为您没有证据或控制为每个类生成唯一ID - 除非您使用某种(抽象)工厂访问私有构造函数或某种类型的全局注册表(见下文)。
    2. 使用一些辅助工具,在其中注册日志记录类并生成唯一ID(类似注册类) 对于简单的日志记录目的,恕我直言,这是膨胀,与1)相比不会增加任何价值。
    3. 结论: 我会选择1)如果人们的可读性受到关注,2)如果你只想要一些数字来区分日志信息(例如管道和过滤)。

答案 1 :(得分:1)

您可以通过CRTP适配器轻松生成ID(如果您可以稍微修改一下类)

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;
}

答案 2 :(得分:0)

如果只有几个类实例,我建议您引入一个字符串成员,并在创建对象时使用唯一名称对其进行初始化。它将帮助您阅读日志。默认情况下,它可以使用对象的地址进行初始化。