如何在C++中的对象之间共享公共资源

how to share common resource amongst objects in c++

在 C++ 中,我经常 运行 遇到这个问题并且总是感到困惑。假设有多个级别的 classes。每个级别都在实例化 class ,它是下面的级别。例如。低于 level1 实例化 level2_a 和 b(在实际情况下还有更多)。 现在叶级对象需要执行一些操作。简单的例子,假设叶级对象需要将一些信息转储到状态控制台。所有叶级对象都需要这样做。在对象之间共享此“状态控制台”指针的最佳方式是什么(这些对象可能有 100 个)?

  1. 是否都需要存储指向它的指针?
  2. 或者将“状态控制台”指针传递给某个成员函数调用,然后它可以用来转储日志。

另一个这样的例子,他们都需要共享一个堆栈,当它们被销毁时,它们会在上面传递一些信息?如何在所有这些叶级对象之间共享堆栈指针

示例:

class level2_a
{
<properties here differ from level2_b>
public:
    ~level2_a()
    {
        // dump some info into a common stack here
    }
    void dump_change_to_value(int newval)
    {
       // need a console pointer here 
       // but can't be singleton because there's 1 per window
    }
};

class level2_b
{
<properties here differ from level2_a>
public:
    ~level2_b()
    {
        // dump some info into a common stack here
    }
    void dump_change_to_value(int newval)
    {
       // need a console pointer here 
       // but can't be singleton because there's 1 per window
    }
};
class level1
{
private:
    level2_a* ml2_a;
    level2_b* ml2_b;    
public:
    <func members..>
};


如何实现stack/console在level2_a和b

之间的共享

通常,我通过通常是单例的co-class在基础class中设置记录器。

我显然总是定义一些基本的记录器:

  • 空记录器(不打印任何内容),
  • 控制台记录器(标准输出/错误),
  • 文件记录器(是否合并stdout/stderr)。

很明显,事实上,它是相同的 class,但实例化了不同的文件句柄。内部单例实例存储在映射中,其中关键部分是传递给 getInstance 方法的值的元组。然后,一旦实例已知,每个 class 使用它的人都会将其存储在 shared_ptr.

默认是在基础 class 中设置您的记录器,通过在创建新派生实例时将用作“默认记录器”的静态属性。但是每个实例也可以设置自己的“私有”记录器,用于调试目的...例如,您可以将“NullLogger”设置为基础class,并将“FileLogger”设置为您当前调试的派生class.

而且,显然,您的程序的其余部分仍然可以使用“SysLogger”在集中位置继续正常日志,例如 rsyslog 或类似的东西。

所有这些仅依赖于保存默认值的静态成员、真正使用的普通属性(在记录器 setter 的构造函数 and/or 中设置),以及明显的虚拟方法。

请注意,“默认”表示“记录器在实例化时连接”,因此更改默认记录器不会传播到所有子实例...除非您在访问记录器时不断使用三元运算符(使用类似于(mThisLogger?mThisLogger:sDefLogger)->log(...) 可以放在一个内联的私有继承函数中)。

好的部分是您不必在初始连接后关心记录器,如果需要它甚至会自动传播(只需要 mutexes/signals 更改它而不会弄乱一切)。但是您仍然可以更改特定实例的记录器,这样您就可以为该实例设置不同的详细级别,或者将日志发送到更方便的目的地(如干净的控制台) , 独立文件, ...) 而无需更改代码中的任何其他内容,如下所示:

#ifdef _DEBUG   // or a "if (isDebug())" if you have such a function...
  annoyingInstance->setLog(allLoggersNamespace::DebugLogger);
  annoyingInstance->setLogLevel(Logger::FullTrace);
#endif