基于类类型的引用计数实例

Reference-counting instances of classes based on their types

本文关键字:实例 引用 于类 类型      更新时间:2023-10-16

请考虑以下代码:

struct I
{
    SomeInternalState m_internalState;
};
struct S
{
    I * m_i;
    set_I (I * i)
    {
        m_i = i;
        makeSomeChangesToTheInternalStateOfI(m_i);
    }
};
struct S_1 : S { ... };
struct S_2 : S { ... };
...
struct S_n : S { ... };

给定S_1实例的任意计数,... 可以创建S_n,并且所有set_I()只会调用一次。

现在,我想要S_1的实例,... S_n每个I类型的S_x实例中makeSomeChangesToTheInternalStateOfI()一次,以便我可以使用相同的I实例从同一类S_x的不同实例调用set_I(),并确保I的内部状态仅在第一次调用期间被修改。

可能的决定是将一些调度表放入I,但我想不出一个明智的键,仅基于S_x实例的类型,不涉及所有可能类型的任何手写"运行时类型 id"常量S_1,... S_n .

我该怎么做?

编辑:

我应该强调的几点:

1(一次可以有多个I实例,S_x类应该能够更改I的多个实例的状态,但每个实例只能更改一次。那是:

I i1, i2;
S_1 s1a, s1b;
S_2 s2a, s2b;
// all possible combinations:
s1a.changeStateOfI(i1);
s1b.changeStateOfI(i1);
s2a.changeStateOfI(i1);
s2b.changeStateOfI(i1);
s1a.changeStateOfI(i2);
s1b.changeStateOfI(i2);
s2a.changeStateOfI(i2);
s2b.changeStateOfI(i2);

在这个片段中,i1i2的状态只能通过S_1的方法(通过s1a(改变一次,S_2的方法(通过s2a(改变一次。

2(我想,引用计数可以用来解决问题 - 没有必要确切地知道初始化发生了多少次,知道它是否发生了就足够了。

编辑2

我已经将n.m.的建议标记为答案,尽管我的最终解决方案略有不同。这里是,以便其他人也可以使用它:

struct AbstractS
{
    I * m_i;
    virtual void set_I (I * i) = 0;
};

template <typename self_T>
struct RegS : AbstractS
{
    static std::set<I *> s_registeredContexts;
    virtual void set_I (I * i)
    {
        m_i = i;
        if (i == NULL || s_registeredContexts.count(i) > 0) return;
        makeSomeChangesToTheInternalStateOfI(i);
        contexts.insert(i);
    }
};
template <typename self_T>
std::set<I *> InterpreterState<self_T>::s_registeredContexts;

struct S_1 : RegS<S_1> { ... };
struct S_2 : RegS<S_2> { ... };
...
struct S_n : RegS<S_n> { ... };

n.m. 的变体相比,不同之处在于我在这里使用了 CRTP 模式,而不是枚举实例化,这也是我想避免的事情。

您可以使用typeinfo作为键,但这是一个坏主意。不应计算程序中的类型。让我用一个简单的例子来解释。

假设您有一个 Vehicle 类型及其后代 CarTruckBike 。每个类调用函数一次。目前为止,一切都好。现在,出于完全不相关的原因,您需要处理SUV,赛车,垃圾车,三轮车,红色汽车,ReddishCars和YellowishReddishWithGreenishTintCars。你关于调用函数的次数的决定应该与你关于为每种情况引入或不引入单独类的决定完全正交。

因此,您需要一些东西来标记您的车辆为不同或相似,只是为了为每个一堆相似的对象调用一次您的函数。实现此目的的一种方法是使用类模板和一堆类型参数(任何类型的类型参数(。

class ChangerOfInternalStateOfI
{
  public:
    ChangerOfInternalStateOfI (I* i) { 
      makeSomeChangesToTheInternalStateOfI(i); 
    }
};
template <int n>
class S_N : public S
{
  public:
    S_N() {
       static ChangerOfInternalStateOfI changer;
    }
};
typedef S_N<1> S_1;
typedef S_N<2> S_2;

你可以使用枚举而不是int,或者类型名,并不重要。关键是所有的 ChangerOfInternalStateOfI 都是不同的,因为它们属于不同的类,并且每个构造函数将被调用一次。

如果提到的静态数据成员 n.m. 的方式不符合目标,在I中有一个包含类型处理的集合怎么样?
由于type_info本身并不具有可比性,因此一个简单的包装器 type_info_在以下代码中使用。如果必须多态地进行类型检查(通过基类 S(,需要运行时类型信息。所以我changeStateOfI变得virtual.

#include <typeinfo>
#include <set>
using namespace std;
struct type_info_ {
  type_info const *t;
  type_info_( type_info const* t ) : t( t ) {}
  bool operator<( type_info_ const& x ) const { return t->before( *x.t ); }
};
struct I {
  set< type_info_ > types;
  void f( type_info const& t, char const* s ) {
    if ( types.insert( type_info_( &t ) ).second ) { puts( s ); }
  }
};
struct S {
  virtual void changeStateOfI( I& i, char const* s ) {
    i.f( typeid( *this ), s );
  }
};
struct S_1 : S {};
struct S_2 : S {};
int main() {
  I i1, i2;
  S_1 s1a, s1b;
  S_2 s2a, s2b;
  s1a.changeStateOfI(i1, "s1a i1");
  s1b.changeStateOfI(i1, "s1b i1");
  s2a.changeStateOfI(i1, "s2a i1");
  s2b.changeStateOfI(i1, "s2b i1");
  s1a.changeStateOfI(i2, "s1a i2");
  s1b.changeStateOfI(i2, "s1b i2");
  s2a.changeStateOfI(i2, "s2a i2");
  s2b.changeStateOfI(i2, "s2b i2");
}

上面的代码打印s1a i1s2a i1s1a i2s2a i2在我的环境中。