动态取消引用n级指针

时间:2018-07-20 18:32:06

标签: c++ templates pointers dereference

假设一个n维数组作为模板参数传递,并且应该遍历才能将其保存到文件中。首先,我想找出数组组成的元素的大小。在那里,我尝试取消对指针的引用,直到我在[0] [0] [0] ... [0]处获得第一个元素。但是我已经在这个阶段失败了:

/**
 * @brief save a n-dimensional array to file
 *
 * @param arr: the n-level-pointer to the data to be saved
 * @param dimensions: pointer to array where dimensions of <arr> are stored
 * @param n: number of levels / dimensions of <arr>
 */
template <typename T>
void save_array(T arr, unsigned int* dimensions, unsigned int n){ 
        // how to put this in a loop ??       
        auto deref1 = *arr;
        auto deref2 = *deref1;
        auto deref3 = *deref2;
        // do this n times, then derefn is equivalent to arr[0]...[0], 42 should be printed
        std::cout << derefn << std::endl;
        /* further code */
}

/*
 * test call
 */
int main(){
        unsigned int dim[4] = {50, 60, 80, 50}
        uint8_t**** arr = new uint8_t***[50];
        /* further initialization of arr, omitted here */
        arr[0][0][0][0] = 42;
        save_array(arr, dim, 4);
}

从内存的角度考虑这一点时,我想对给定地址执行n间接加载。

我看到了昨天提出的一个相关问题: Declaring dynamic Multi-Dimensional pointer

这对我也有很大帮助。有一条评论指出,这是不可能的,因为必须在编译时知道所有表达式的类型。就我而言,实际上已经知道了一切,save_array的所有调用方在通过之前都会进行n硬编码。因此,我认为这可能只是在正确的地方定义我还无法做到的事情。

我知道我正在用C ++编写C风格的代码,并且可以使用类等实现此目的,但是我的问题是:是否可以通过迭代或递归方法实现n级指针取消引用?谢谢!

2 个答案:

答案 0 :(得分:0)

为什么不只使用带有多个子节点的树之类的数据结构。

假设您需要存储n个维度数组值,创建一个指向第一个维度的节点。假设您的第一个维度长度为5,那么您有5个子节点,如果第二个维度大小为10,那么对于这5个节点中的每一个,您都有10个子节点,依此类推。...

类似

struct node{
    int index;
    int dimension;
    vector<node*> children;
}

遍历树更容易,更整洁。

答案 1 :(得分:0)

首先:您真的需要锯齿状的阵列吗?您是否想要某种稀疏数组?因为否则,您是否不仅可以将n维结构展平为单个长数组?那不仅会导致代码简单得多,而且更有可能更有效。

话虽如此:可以肯定地做到。例如,仅使用递归模板并依靠重载来剥离间接级别,直到到达最底端为止。

template <typename T>
void save_array(T* arr, unsigned int* dimensions)
{
    for (unsigned int i = 0U; i < *dimensions; ++i)
        std::cout << ' ' << *arr++;
    std::cout << std::endl;
}

template <typename T>
void save_array(T** arr, unsigned int* dimensions)
{
    for (unsigned int i = 0U; i < *dimensions; ++i)
        save_array(*arr, dimensions + 1);
}

您甚至不需要显式指定间接访问次数n,因为该数目由指针类型隐式给出。

您也可以执行基本相同的技巧来分配/取消分配数组:

template <typename T>
struct array_builder;

template <typename T>
struct array_builder<T*>
{
    T* allocate(unsigned int* dimensions) const
    {
        return new T[*dimensions];
    }
};

template <typename T>
struct array_builder<T**> : private array_builder<T*>
{
    T** allocate(unsigned int* dimensions) const
    {
        T** array = new T*[*dimensions];

        for (unsigned int i = 0U; i < *dimensions; ++i)
            array[i] = array_builder<T*>::allocate(dimensions + 1);

        return array;
    }
};

就这样,您需要部分专业化,因为使用重载的方法仅在可以从参数推断类型时才起作用。由于函数不能部分地专门化,因此必须将其包装在这样的类模板中。用法:

unsigned int dim[4] = { 50, 60, 80, 50 };
auto arr = array_builder<std::uint8_t****>{}.allocate(dim);
arr[0][0][0][0] = 42;
save_array(arr, dim);

希望我什么都没忽略;在公开场合公开如此众多的间接指令可能会使真正的快速操作造成极大的混乱,这就是为什么我强烈建议不要在实际代码中进行此操作,除非绝对不可避免。同样,new的原始用法在所有地方都很棒。理想情况下,您将使用例如std::unique_ptr。或者,更好的是,按照注释中的建议嵌套std::vectors ...