简体   繁体   English

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

[英]how to share common resource amongst objects in c++

In C++, I frequently run into this problem and always left confused.在C++中,我经常遇到这个问题,总是一头雾水。 Suppose there are multiple levels of classes.假设有多个级别的类。 Each level is instantiating the class which is a level below.每个级别都在实例化 class,这是下一个级别。 Eg below level1 instantiates level2_a and b(there are more in real case).例如,低于 level1 实例化 level2_a 和 b(在实际情况下还有更多)。 Now some operation the leaf level object needs to perform.现在叶级 object 需要执行一些操作。 Simple example, say the leaf level object needs to dump some information onto a status console.简单的例子,假设叶级 object 需要将一些信息转储到状态控制台。 And all the leaf level objects need to do this.所有叶级对象都需要这样做。 What is the best way to share this "status console" pointer amongst the objects (there could be 100s of these objects)?在对象之间共享这个“状态控制台”指针的最佳方式是什么(这些对象可能有 100 个)?

  1. Do they all need to store a pointer to it?他们都需要存储指向它的指针吗?
  2. Or pass the "status console" pointer to some member function call which it can then use to dump a log.或者将“状态控制台”指针传递给某个成员 function 调用,然后它可以用来转储日志。

Another such example they all need to share a stack onto which they convey some info when they are destroyed?另一个这样的例子,他们都需要共享一个堆栈,当它们被销毁时,它们会在上面传递一些信息? How to share the stack pointer amongst all these leaf level objects如何在所有这些叶级对象之间共享堆栈指针

Example:例子:

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


How to accomplish sharing of the stack/console amongst level2_a and b如何在 level2_a 和 b 之间完成堆栈/控制台的共享

Usually, I set up the logger in the base class, through a co-class that is often a singleton.通常,我通过通常为 singleton 的共同类在 class 基地设置记录器。

I obviously always define some basic loggers:我显然总是定义一些基本的记录器:

  • Null logger (don't print anything), Null 记录器(不打印任何东西),
  • Console logger (standard output / error),控制台记录器(标准 output / 错误),
  • File logger (merged stdout / stderr or not).文件记录器(是否合并stdout / stderr )。

It's obvious that, in fact, it's the same class but instanciated with different file handles.很明显,实际上,它是相同的 class,但实例化了不同的文件句柄。 The internal singleton instances are stored in a map, where the key part is the tuple of values passed to the getInstance method.内部的 singleton 实例存储在一个 map 中,其中关键部分是传递给getInstance方法的值的元组。 Then, once the instance is known, each class using it stores it in a shared_ptr .然后,一旦实例已知,每个使用它的 class 都会将其存储在shared_ptr中。

Default is to set up your logger in the base class, through static attributes that will be used as "default logger" when a new derivated instance is created.默认是通过 static 属性在基础 class 中设置您的记录器,当创建新的派生实例时,这些属性将用作“默认记录器”。 But each instance can also set its own, "private" logger, for debug purpose... For example, you can set the "NullLogger" to base class, and set the "FileLogger" to your currently debugged derivated class.但是每个实例也可以设置自己的“私有”记录器,用于调试目的...例如,您可以将“NullLogger”设置为基数 class,并将“FileLogger”设置为当前调试的派生 class。

And, obviously, the rest of your program can still use a "SysLogger" to continue the normal logs in a centralized place, like rsyslog or anything like this.而且,显然,您程序的 rest 仍然可以使用“SysLogger”在集中位置继续正常日志,如rsyslog或类似的东西。

All this rely only on static members that hold the default values, normal attributes (set in constructor and/or in logger's setter) that are the ones really used, and obviously virtual methods.所有这一切仅依赖于 static 个成员,这些成员拥有默认值、真正使用的普通属性(在构造函数和/或记录器的设置器中设置),以及明显的虚拟方法。

Note that "default" means "logger connected at instanciation", so changing the default logger isn't propagated to all child instances... Unless you constantly use a ternary operator when accessing logger (with a line similar to (mThisLogger?mThisLogger:sDefLogger)->log(...) that can be put in an inline private, inherited function).请注意,“默认”表示“记录器在实例化时连接”,因此更改默认记录器不会传播到所有子实例......除非您在访问记录器时不断使用三元运算符(使用类似于(mThisLogger?mThisLogger:sDefLogger)->log(...)可以放在一个内联的私有继承函数中)。

The nice part is that you don't have to care about the logger after its initial connection, and it's even propagated automatically if needed (simply needs mutexes/signals to change it without messing up everything).好的部分是您不必在初始连接后关心记录器,如果需要它甚至会自动传播(只需要互斥锁/信号来更改它而不会弄乱一切)。 But you can still change the logger for a particular instance, so that you can set a different verbosity level just for this instance , or send the log to a more convenient destination (like a clean console, standalone file, ...) without changing anything else in the code, with something like this:但是您仍然可以更改特定实例的记录器,以便您可以仅为该实例设置不同的详细级别,或者将日志发送到更方便的目的地(如干净的控制台、独立文件...)而不更改代码中的任何其他内容,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM