我正在编写一个存储点的std::vector的程序,我还为其中的一些点加载了一个“约束”的std::unordered_map,然后将其应用到点数组中。目前,这些限制的形式如下:
+---------------+
|Type |Value |
+---------------+
|Constant| 1.0 |
| | |
|Lerp | n/a |
| | |
|Loop | n/a |
| | |
|... | |
+--------+------+有几种类型,但其中只有一种(常量)实际上需要存储一个值(在本例中是双值)。在原型中,我选择存储所有类型的值,只使用了一个std::pair<ConstraintType, double>。它可以工作,但感觉很糟糕;虽然常量是最常见的点类型,存储几千个未使用的双倍在现代硬件上也是可以忽略不计的,但我不喜欢这种浪费。不过,我想不出更好的办法了。如果我从基类派生,据我所见,我将得到一个只有一个虚拟方法的基类(您的派生类型是什么?)如果它是常数,我就把它降下来,得到它的值。糟透了。我唯一考虑的其他想法是将常量保存在一个单独的std::unordered_map中,但是如果我添加另一个需要一个值(或两个)的约束,我该怎么办呢?它似乎没有规模。
我在这里肯定遗漏了一些东西,这类事情应该是微不足道的。我们将感激地接受这些建议(我相信这将是一个令人欣慰的时刻)。
发布于 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,但使用指针(特定的约束类型不需要多态,因此可以节省指向虚拟表的指针所需的空间)。
发布于 2016-01-25 22:30:31
如果您关心内存的使用,一种可能性(并不是特别推荐的)是只有一个double (没有pair),然后用一些非常罕见的双常量来枚举其他的所有内容。例如,
const double Lerp = -9e+200;
const double Loop = -9e+201;其他不是Lerp或Loop的东西都是实际的双值。
您可以查阅IEEE浮点数的定义,以选择离现实边缘很近的数字,因为它们在实践中永远不会出现。如果是这样的话,你应该质疑你的算法,以及它是否应该在googol上产生值。
当然,如果您关心的是空间,那么使用float代替。对于输入数据,它可能足够好(当然,在内部,使用double进行计算)。
如果将任何内容添加到双enum中,比如真正的double,甚至只是一个字节,那么您将对齐所有数据,或者使用性能丢失支付,或者用额外的字节填充结构,从而使double值字段对齐。
发布于 2016-01-25 22:43:58
就我个人而言,我会选择带有虚拟函数的类,正如axalis所描述的:它是一个干净的面向对象的设计,易于维护和可扩展,例如,如果您想添加一种新的约束类型。
仅用于记录的:还有另一种方法,使用函子和绑定或lambda:
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; 这比简单的表更不方便,但是如果您有许多不同类型的约束,其中一些约束是在流上定义的,那么它可能是另一种选择。
https://stackoverflow.com/questions/35002999
复制相似问题