基于类类型的引用计数实例
Reference-counting instances of classes based on their types
请考虑以下代码:
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);
在这个片段中,i1
和i2
的状态只能通过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
类型及其后代 Car
、 Truck
和 Bike
。每个类调用函数一次。目前为止,一切都好。现在,出于完全不相关的原因,您需要处理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 i1
、s2a i1
、s1a i2
、s2a i2
在我的环境中。
- 对显式实例化的模板函数的未定义引用
- 重载运算符*以获取对另一个类的实例的引用
- 为什么我不能引用指向实例化对象的函数的指针?
- <Base> <Derived> 具有相同原始指针共享引用的 shared_ptr 和 shared_ptr 实例是否计数?
- 返回引用实例和非引用实例(return mystr & vs mystr)之间的区别是什么?
- 请参阅在 Visual Studio 2019 中捕获 std::exception 时对函数模板实例化消息的引用
- 将元组和整型实例合并到引用元组中
- C++ 为什么在定义的编译和链接之前引用外部实例的程序
- 是否允许使用初始值设定项列表将const数组引用实例化为构造函数参数
- 引用的静态强制转换强制模板实例化,其中不完整的类型很好
- 为什么不能在实例化对基类的引用的同时实例化指向派生类的指针?
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- 超出返回引用的单一实例生存期
- 反向函数不反转类实例化的引用字符串
- 通过引用将私有类实例传递到另一个类 C++ 的"get"函数中
- 多个实例保存对unique_ptr的引用
- 类模板实例化和通用引用
- 对从静态实例引用的类模板的静态成员的未定义引用
- 如何正确格式化类实例引用
- 如何在类构造函数中存储实例引用