c++ - 如何有效地将 float 别名为命名成员和数组元素?

标签 c++ arrays reference alias kdtree

我正在实现基于粒子的流体模拟。为了表示速度、加速度等 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 其中后者被初始化为指向相应的 floats 在数组中。我认为它们会被优化掉,因为它们在编译时是已知的,并且显然在初始化后不能更改值,但即使进行了优化,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/

相关文章:

c++ - 是否存在 "int"会导致结构填充的环境?

c++ - 如何随机化程序的窗口标题?

java - 使用变量引用指向其他类的静态成员

c++ - 从指针升级到引用——如何处理 NULL 到引用

java - C++/Java 引用变量

c++ - boost program_options 开/关标志

c++ - 源代码管理中的 .vcxproj

C - 将未初始化的变量传递给数组元素

Python 数组与列表

javascript - 读取文件并将其存储在javascript中的数组中