C ++如何将类数组视为主类型数组?

时间:2014-03-10 22:01:33

标签: c++ arrays

我有这段代码:

class Vector3
{
    public:
        Vector3() : x(values[0]), y(values[1]), z(values[2])
        { x = y = z = 0; }

        float& x;
        float& y;
        float& z;
    private:
        float[3] values;
};

class Model
{
    public:
        Vector3 vertices[64];
};

我正在做这个矢量类,因为我想在代码中处理XYZ的值,但对于某些操作,我需要一个连续的数组要传递给函数的值。 所以vertices[64]的整个数组需要[x0][y0][z0][x1][y1][z1][x2][y2][z2]等。

但如果我这样做:

//Get first address:
void* firstAddress = &vertices[0];
//Or
void* firstAddress = vertices;

我没有连续数组,因为我需要它(数据全部搞砸了),我猜它是因为我在Vector3类中的指针。 我有什么方法可以获得我想要的功能吗? (有一个浮点数,但处理值为x,y,z)

6 个答案:

答案 0 :(得分:1)

您可以改为使用成员函数:

class V3
{
    float data[3];

public:
    V3() : data{0,0,0} {}

    float & x() { return data[0]; }
    float & y() { return data[1]; }
    float & z() { return data[2]; }
};

你也可以省略构造函数并有一个聚合,如果那更合适的话。

答案 1 :(得分:1)

首先,标准没有定义如何实现引用,但是它们几乎肯定会占用类中的实际内存而非指针成员,破坏了你希望的连续数据包.... / p>

如果您的焦点更多地放在顶点容器上,并且您只想让x / y / z成员访问其中的元素,那么您可以尝试以下方法:

template <size_t N>
class Vertices
{
  public:
    class Proxy
    {
      public:
        Proxy(float* p) : x(p[0]), y(p[1]), z(p[2]) { }
        float& x;
        float& y;
        float& z;
    };

    Proxy operator[](size_t n) { return Proxy(&d_[n * 3]); }
    const Proxy operator[](size_t n) const { return Proxy(&d_[n * 3]); }

  private:
    float d_[N * 3];
};

答案 2 :(得分:0)

你拥有的values指针数组(指向3个floats的数组)包含3个float引用(xy,{{ 1}})。你可能更喜欢蚂蚁:

z

答案 3 :(得分:0)

对于保证连续的数组,您需要将数据复制到数组中,或者使用特定于编译器的内存布局保证,特别是

  • 没有填充,

如果您还希望将数组的三元组作为Vector3实例访问,那么

  • 在任意地址访问Vector3不会导致陷阱或效率低下(我们在这里进入 alignment )。

恰巧一些常见的库(如OpenCV)会对其内部图像缓冲区做出这样的假设。

但我不完全确定我见过的代码不适合平台。所以,在实践中你有这些选择:

  • 将数据连续复制到数组(或从中复制)和/或

  • 使用提供此类功能的现有库,例如OpenCV。

请注意,使用成员函数而不是引用会购买任何东西。对于连续的数组问题,它确实使Vector3可以分配。


在进一步思考时,我可能过于高兴地写了上述内容。如果您可以保证总大小3*sizeof(float),并且这几乎是给定的(只是删除那些引用),那么您可以保证可以在任何可以容纳{{{{}}的地址访问Vector3 1}},因为C ++保证数组没有填充,并且因为在这样的数组中,float可以在任何可以容纳Vector3的地址处结束。因此,实践中的问题减少了,无法支持无法使float大小为Vector3的编译器或编译器配置。

3*sizeof(float)

使用没有中间访问说明符的成员保证增加地址顺序的事实。

免责声明:关闭袖口代码,不要被编制者的手接触。

答案 4 :(得分:0)

如果我理解您对模型中连续数据的要求,那么您的Vector实际上是模型中特定三重数据的别名。不需要浮动存储。

class Model

    class Vector
        Vector(Model *model_, size_t idx_) : model(model_),idx(idx_) { };
        Model *model;
        size_t idx;
        float & x() { return model->data[3*idx]; }
        float & y() { return model->data[3*idx+1]; }
        float & z() { return model->data[3*idx+2]; }

    float data[64 * 3];
    Vector vectors[64];

    Model() {
        ...
        for( size_t ii = 0; ii < 64; ii++ ) {
            vectors[ii] = new Vector(this,ii);
        }

     Vector & vector(size_t idx) { return vectors[ii]; }

答案 5 :(得分:0)

如果你将Vector3类保持为POD,你应该能够简单地将顶点转换为浮点数组:

struct Vector3 {
    float x;
    float y;
    float z;
};

class Model
{
    public:
        Vector3 vertices[64];
        float* data() {
            return reinterpret_cast<float*>(vertices);
        }
};

int main() {
    Model m;
    for(int i = 0; i < 64; ++i) {
        m.vertices[i] = {10+i,100+i,1000+i};
    }
    float *data = m.data();

    for(int i= 0; i < 64*3; ++i) {
        std::cout << data[i] << ", ";
    }
}

唯一的问题可能是结构的Allignment,但是如果你使用c ++ 11,有一种标准方法可以使用allignas alignas(alignof(float[3]))来对结构进行分配。我不知道这是否真的需要。 此外,c ++ 11提供了很多关于如何处理Vector3的选项,同时仍将其视为POD类型。