正确"多态"存储枚举的方式,有时还包含一些数据

时间:2016-01-25 21:45:56

标签: c++ oop

我正在制作一个程序,我存储了std::vector个点,我还加载了std::unordered_map个约束"对于其中一些点,然后将其应用于点数组。目前,约束形式为:

+---------------+
|Type    |Value |
+---------------+
|Constant|  1.0 |
|        |      |
|Lerp    |  n/a |
|        |      |
|Loop    |  n/a |
|        |      |
|...     |      |
+--------+------+

有几种类型,但只有其中一种(常量)实际需要存储一个值(在本例中为double)。在原型中,我选择存储所有类型的值,并使用了std::pair<ConstraintType, double>。它有效,但感觉很糟糕;虽然Constant是最常见的点类型,但在现代硬件上存储甚至几千个未使用过的双打也是相当微不足道的我不喜欢浪费。但我无法想到更好的方法。如果我从基类派生出来,据我所知,我最终会得到一个基类,只有一个虚拟方法(你的派生类型是什么?)然后如果它&#39 ; s常常我垂头丧气并获得价值。呸。我想到的唯一另一个想法是将常量保存在单独的std::unordered_map中,但如果我添加另一个需要值(或两个)的约束,我该怎么办?它似乎没有规模。

我肯定在这里遗漏了一些东西,这种事情应该是微不足道的。我会非常感激地接受建议(我确信这将成为一个校长时刻)。

3 个答案:

答案 0 :(得分:3)

你可以将多态类存储为指针(例如unique_ptr),但是你不会获得太多的收益(因为指针会有4或8个B,而指向虚拟的指针会有另外4-8个B指针)表,所以在32位应用程序上至少额外增加8个B,这与每次存储双倍相同,然后它会慢一些。

对于检查,您可以通过提供(纯)虚拟布尔检查(const Point&amp;)方法或类似方法来执行此操作,这将以多态方式检查约束(因此约束类型可以包含任何内容并且将是适当检查。)

我还在想你可以使用boost :: any或boost :: variant,但遗憾的是,这并不会有多大帮助。 boost :: any使用类型擦除来保存类型,因此有一个指向内部虚拟持有者的指针(它还有一个指向虚拟表的指针)。

boost :: variant需要预先知道所有类型,这可能适用于此处。然而,boost :: variant中的存储必须与它可以容纳的最大类型一样大(因此没有任何改进,因为每个实例基本上需要与存储double的最大约束相同的空间)。但是,boost :: variant的一个优点是可以通过使用boost :: static_visitor在没有虚拟运行时调度的情况下完成检查,因此速度更快。

一般来说,为了真正节省最大空间量,我没有看到比在不同列表中保留不同约束类型(根据大小)更好的选择。第二个最好的选择是IMHO使用boost :: variant,但是使用指针(特定的约束类型不需要是多态的,所以你节省了指向虚拟表所需的空间)。

答案 1 :(得分:1)

如果你担心内存使用,一种可能性(不是非常推荐)就是只有一个double(无pair)并用一些非常罕见的双常量枚举其他所有内容。例如,

const double Lerp = -9e+200;
const double Loop = -9e+201;

以及其他非LerpLoop的内容都是实际的双倍值。

您可以查找IEEE浮点数的定义,以选择到目前为止接近现实边缘的数字,这些数字在实践中永远不会出现。如果他们这样做,你应该质疑你的算法以及它是否应该通过googol产生值。

当然,如果您担心空间,请改用float。它对于输入数据来说可能已经足够了(在内部,当然使用double进行计算)。

如果你向double添加任何内容,就像真正的enum一样,即使只是一个字节,你也会取消所有数据的对齐,或者使用性能缺失付费或用额外的字节填充结构,以便double值字段已对齐。

答案 2 :(得分:0)

我个人选择具有虚函数的类,如 axalis 所述:它是一个干净的面向对象设计,易于维护和扩展,例如,如果你想要的话添加新类型的约束。

仅限记录:可能有另一种方式,使用仿函数和绑定或lambdas:

map< Point, function<bool(Point&)>> cst;   // your map
cst [p1] = check_Lerp;                     // predefined function
cst [p2] = bind(check_Constant, _1, 2.0);  // fixing a parameter to have only one free parameter left
cst [p3] = [](Point& p){ return check_Constant(p,2.0); }; // using lambda for more complex constraints

要检查矢量的合规性,您需要:

if (all_of(v.begin(), v.end(), 
         [&](Point&p) { if (cst.find(p)==cst.end()) return true; else return cst[p](p);}))
    cout<<"everythin is ok"<<endl; 
else cout << "not compliant"<<endl; 

这比简单的表更不方便,但如果你有许多不同类型的约束,有些是在流上定义的,那么它可能是另一种选择。