首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >纠正存储枚举的“多态”方法,有时还存储一些数据

纠正存储枚举的“多态”方法,有时还存储一些数据
EN

Stack Overflow用户
提问于 2016-01-25 21:45:56
回答 3查看 189关注 0票数 3

我正在编写一个存储点的std::vector的程序,我还为其中的一些点加载了一个“约束”的std::unordered_map,然后将其应用到点数组中。目前,这些限制的形式如下:

代码语言:javascript
复制
+---------------+
|Type    |Value |
+---------------+
|Constant|  1.0 |
|        |      |
|Lerp    |  n/a |
|        |      |
|Loop    |  n/a |
|        |      |
|...     |      |
+--------+------+

有几种类型,但其中只有一种(常量)实际上需要存储一个值(在本例中是双值)。在原型中,我选择存储所有类型的值,只使用了一个std::pair<ConstraintType, double>。它可以工作,但感觉很糟糕;虽然常量是最常见的点类型,存储几千个未使用的双倍在现代硬件上也是可以忽略不计的,但我不喜欢这种浪费。不过,我想不出更好的办法了。如果我从基类派生,据我所见,我将得到一个只有一个虚拟方法的基类(您的派生类型是什么?)如果它是常数,我就把它降下来,得到它的值。糟透了。我唯一考虑的其他想法是将常量保存在一个单独的std::unordered_map中,但是如果我添加另一个需要一个值(或两个)的约束,我该怎么办呢?它似乎没有规模。

我在这里肯定遗漏了一些东西,这类事情应该是微不足道的。我们将感激地接受这些建议(我相信这将是一个令人欣慰的时刻)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-01-25 22:01:10

您可以将多态类存储为指针(例如,unique_ptr),但是您不会获得多少(因为指针将有4或8B,而虚拟表将有另一个4-8B指针,因此32位应用程序上至少需要额外的8B,这与每次存储双值相同,然后速度会变慢)。

至于检查,您可以通过提供一个(纯)虚拟bool check(const Point &)方法或类似的方法来做到这一点,而无需下行转换,该方法将多形性地检查约束(因此约束类型可以包含任何内容,并将被适当地检查)。

我还在想,您可以使用boost::any或boost::variant,但不幸的是,这并没有多大帮助。boost:任何使用类型擦除来保存类型的,所以内部有一个指向虚拟持卡器的指针(它也有指向虚拟表的指针)。

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

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

票数 3
EN

Stack Overflow用户

发布于 2016-01-25 22:30:31

如果您关心内存的使用,一种可能性(并不是特别推荐的)是只有一个double (没有pair),然后用一些非常罕见的双常量来枚举其他的所有内容。例如,

代码语言:javascript
复制
const double Lerp = -9e+200;
const double Loop = -9e+201;

其他不是LerpLoop的东西都是实际的双值。

您可以查阅IEEE浮点数的定义,以选择离现实边缘很近的数字,因为它们在实践中永远不会出现。如果是这样的话,你应该质疑你的算法,以及它是否应该在googol上产生值。

当然,如果您关心的是空间,那么使用float代替。对于输入数据,它可能足够好(当然,在内部,使用double进行计算)。

如果将任何内容添加到双enum中,比如真正的double,甚至只是一个字节,那么您将对齐所有数据,或者使用性能丢失支付,或者用额外的字节填充结构,从而使double值字段对齐。

票数 1
EN

Stack Overflow用户

发布于 2016-01-25 22:43:58

就我个人而言,我会选择带有虚拟函数的类,正如axalis所描述的:它是一个干净的面向对象的设计,易于维护和可扩展,例如,如果您想添加一种新的约束类型。

仅用于记录的还有另一种方法,使用函子和绑定或lambda:

代码语言:javascript
复制
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

要检查向量的依从性,请执行以下操作:

代码语言:javascript
复制
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; 

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35002999

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档