我正在实现基于粒子的流体模拟。为了表示速度、加速度等 vector ,我定义了一个类,如下所示
class Vec3f {
public:
float x, y, z;
// ... bunch of constructors, operators and utility functions
}
我正在使用库 nanoflann 进行 kd 树搜索。为了适应任意类设计,nanoflann 需要一个用户定义的适配器类,然后 kd-tree 类查询该类以获取有关粒子数据集的信息。如 nanoflann 文档中所述,适配器必须提供的一项功能如下。
// Must return the dim'th component of the idx'th point in the class:
inline T kdtree_get_pt(const size_t idx, int dim) const { ... }
问题是这个接口(interface)不能与 x, y, z
表示无缝地工作。天真地,它需要做这样的事情
inline float kdtree_get_pt(const size_t idx, int dim) const {
switch(dim) {
case 0:
return particlearray[idx].x;
case 1:
return particlearray[idx].y;
case 2:
return particlearray[idx].z;
}
}
构建和查询 kd-tree 占用了我应用程序运行时的很大一部分,并且 kd_tree_get_pt
在此过程中被多次查询,因此我需要对其进行优化。以下解决方案应该更快。
class Vec3f {
public:
float values[3];
// ...
}
// Then inside the adaptor class
inline float kdtree_get_pt(const size_t idx, int dim) const {
return particlearrray[idx].values[dim];
}
但是,对于我的方程式,我更喜欢 x, y, z
接口(interface)。现在问题很清楚了,我的问题是如何在不使 kdtree_get_pt
次优的情况下为我的方程保留 x, y, z
符号。
我考虑过的解决方案:
Vec3f
有成员float values[3]
和float& x()
形式的 getter。应该完全优化函数调用,这样这几乎可以工作,但如果可以避免的话,我不想在我的方程式中添加括号。例如,我希望能够编写vec1.x - vec2.x
而不是vec1.x() - vec2.x()
。据我所知,C++ 不提供将函数调用“伪装”为成员变量的方法,不包括我认为不是安全解决方案的预处理器宏。Vec3f 有成员
float values[3]
和float& x, y, z
其中后者被初始化为指向相应的float
s 在数组中。我认为它们会被优化掉,因为它们在编译时是已知的,并且显然在初始化后不能更改值,但即使进行了优化,MSVC++ 似乎实际上存储了float&
,如所示>sizeof(Vec3f)
添加后增加 12 个字节。这使我的数据集的存储大小增加了一倍,这引发了在处理任意大的数据集时缓存未命中的问题。kdtree_get_pt
使用float& values[3]
指向x, y, z
。这可能会消除分支成本,但我不相信额外的间接级别,也不能优化初始化所有 3 个引用的需要,因此它可能比 return particularrray[idx][dim]` 版本慢。kdtree_get_pt
使用reinterpret_cast
或指针魔法直接指向Vec3f
的成员。给定一个Vec3f
对象的地址,我相信x, y, z
保证按顺序存储,第一个存储在与给定的地址相同的地址&
运算符在Vec3f
对象上,但即便如此,我还是很困惑是否存在观察它们的明确定义的方法。
最佳答案
从软件工程的角度来看,最好只通过访问器和修改器函数公开数据。
我建议:
class Vec3f
{
public:
float& operator[](size_t index) { return values[index]; }
float operator[](size_t index) const { return values[index]; }
float& x() { return values[0]; }
float x() const { return values[0]; }
float& y() { return values[1]; }
float y() const { return values[1]; }
float& z() { return values[2]; }
float z() const { return values[2]; }
private:
float values[3];
}
回复:kdtree_get_pt
使用 reinterpret_cast
或指针魔法直接指向 Vec3f
的成员。
这通常是个坏主意。但是,我不认为这是我的建议的问题。
关于c++ - 如何有效地将 float 别名为命名成员和数组元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47658965/