如何让VC ++访问指针作为2D数组

时间:2014-09-13 08:39:06

标签: c++ visual-c++ visual-studio-2012 reference variable-length-array

我正在进行一些图形编程,并且我使用openGL存储了一个二维数组(在程序执行期间大小不一)。 因此,当我去访问它时,我得到的只是一个void pointer

为了使逻辑更容易,我希望编译器假装它是,并将其用作2D数组(因为arr[i][j]ptr[i * y + j]更简洁,更不容易出错。< / p>


我发现这种聪明的投射方法在GCC(在uni的linux机器上)上工作正常:

Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
    glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);

其中基本上转换了内存指针块openGL给了我一个tess X tess 2D数组,并创建了一个指向它的类型的引用。
这允许我访问像vertices[i][j]这样的内存 Vertex只是typedef ed struct,其中包含float s

但是,在我的Windows机器上的家中,VS&#12; 12有一种气势,他们抱怨它需要tess写成constant的整数(具体来说是error C2057: expected constant expression })。
我不明白为什么。

现在,我理解VS doesn't support VLA's,但我不是在这里创建数组,我正在创建一个引用来代替我直到运行时才知道&#39;的大小 因此,如果函数调用之间的大小发生变化,它应该不在乎,对吧?为什么不允许这样做?


不要阻止我尝试使用std::array

std::array<std::array<Vertex, tess>, tess>& vertices;

除了显而易见的references must be initialized之外,这个测试对我没有帮助,因为它仍抱怨expression must have a constant value具体; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression


我对在这里尝试的东西感到茫然,我为reinterpret_cast感到骄傲,并为它做了多么简单的事情,并确信我没有使用违反标准的方法。登记/> 我不想从指针创建std::vector,然后在我完成时将该动态数组中的数据复制回指针位置;当内存块已经只是坐在那里时,效率似乎很低! 没有办法在周围创建一个预先存在的内存块的向量,是吗? ..听起来很傻。

我想看看是否可以在不放弃的情况下完成,只需将其用作Vertex*;想法?
有人可以告诉我为什么它不在VS工作吗? 有什么我可以做的让它工作(VS的扩展/更新)?
VS&#39; 13是否会增加对此的支持?

<子> 我也收到了我无法解释的错误C2087: 'vertices' : missing subscript 除了这些似乎表明VS迫切希望tess保持不变的其他错误:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'

1 个答案:

答案 0 :(得分:0)

那很有趣;我实施了一个类来处理我想要的东西。
它并不像我想的那样安全,但我学到了很多东西 就像我在发现jQuery之前为javascript实现应该是规范的,语法 - 糖的功能一样。

基本上,不是能够做到这一点。

int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);

你必须这样做

MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);

但除此之外它完美无瑕! :d
我最初只编写了一个专门的TwoDArray类,但发现我实际上也有一些3D数组 因此,我没有实现3D版本(当您向下钻取时返回了TwoDArray),而是制作了更通用的内容,可以帮助您处理任意数量的数组。


#include <Windows.h>
#include <iostream>

/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array

C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);

using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
    Type* array;
    //+1 to guard against zero-length-array
    unsigned int bounds[dimension + 1];

public:
    //unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
    //because of how operator[]() tries to construct its return value
    /*constructor*/
    MDAI(Type* array, unsigned int* bounds)
    : array(array)
    {
        std::copy(bounds, bounds + dimension, this->bounds);
    }

    /*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
    MDAI(Type* array, ...)
    : array(array)
    {
        va_list arguments;
        va_start(arguments, array);
        for (int index = 0; index < dimension; ++index)
            bounds[index] = va_arg(arguments, unsigned int);
        va_end(arguments);
    }

    /*drills down one level into the multi dimensional array*/
    MDAI<Type, dimension - 1> operator[](unsigned index) {
        if (dimension < 1) {
            std::cerr << "MDAI is not an array.\n";
            throw 1;
        }
        if (index < 0 || index >= bounds[0]) {
            std::cerr << "Index out of bounds.\n";
            throw 1;
        }

        //figure out how many addresses to jump
        for (unsigned int index2 = 1; index2 < dimension; ++index2)
            index *= bounds[index2];

        return MDAI<Type, dimension - 1>(array + index, bounds + 1);
    }

    /*'dereferences' the array to get a reference to the stored value*/
    Type& operator*() {
        if (dimension > 0) {
            std::cerr << "MDAI is an array.\n";
            throw 1;
        }

        return *array;
    }

    /*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
    operator Type&() {
        return **this;
    }

    /*makes assignment work automagically too!*/
    MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
        **this = value;
        return *this;
    }
};

测试边界的三维数组2-4-3:

void main(unsigned int argC, char** argV) {
    using namespace std;

    int array[2][4][3] = {
        {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9},
            {10, 11, 12}
        },
        {
            {13, 14, 15},
            {16, 17, 18},
            {19, 20, 21},
            {22, 23, 24}
        }
    };

    //cast array to pointer, then interpret
    MDAI<int, 3> mdai((int*)array, 2, 4, 3);
    //testing correct memory access
    cout << 15 << ' ' << mdai[1][0][2] << endl;

    //testing modifcations using mdai are in array
    mdai[0][2][1] = -1;
    cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;

    //testing modifications in array show up in mdai
    array[1][3][2] = -23;
    cout << -23 << ' ' << mdai[1][3][2] << endl;

    //testing automatic type casting
    cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}

它就像我把它作为数组引用一样无缝。

对于编译时的安全性,我希望重新声明operator*(),具体而言; Type& MDAI<Type, 0>::operator*()
所以你只能在&lt; X,0&gt;上调用它 但我无法弄明白。
同样,只有大于0的维度才会显示operator[]() 哦,运行时检查必须足够好