简体   繁体   English

动态取消引用n级指针

[英]Dynamic dereference of a n-level pointer

Suppose a n-dimensional array that is passed as template argument and should be traversed in order to save it to a file. 假设将n维数组作为模板参数传递,并且应该遍历以将其保存到文件中。 First of all I want to find out the size of the elements the array consists of. 首先,我想找出数组组成的元素的大小。 Thereto I try to dereference the pointers until I get the first element at [0][0][0]...[0]. 在那里,我尝试取消对指针的引用,直到我在[0] [0] [0] ... [0]处获得第一个元素。 But I already fail at this stage: 但是我在这个阶段已经失败了:

/**
 * @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);
}

When I think of this from a memory perspective I want to perform a n-indirect load of a given address. 从内存的角度考虑这一点时,我想对给定地址执行n间接加载。

I saw a related question that was asked yesterday: Declaring dynamic Multi-Dimensional pointer 我看到了昨天提出的一个相关问题: 声明动态多维指针

This would help me a lot as well. 这对我也有很大帮助。 One comment states it is not possible since types of all expressions must be known at compile-time. 有一条评论指出,这是不可能的,因为必须在编译时知道所有表达式的类型。 In my case there's actually known everything, all callers of save_array will have n hardcoded before passing it. 在我的情况下,实际上什么都知道,所有save_array调用者在传递之前都会进行n硬编码。 So I think it could be just a matter of defining stuff at the right place what I am yet not able to. 因此,我认为这可能只是在正确的地方定义我还无法做到的事情。

I know I am writing C-style code in C++ and there could be options to achieve this with classes etc., but my question is: Is it possible to achieve n-level pointer dereference by an iterative or recursive approach? 我知道我正在用C ++编写C风格的代码,并且可以使用类等实现此目的,但是我的问题是:是否可以通过迭代或递归方法实现n级指针取消引用? Thanks! 谢谢!

Why not just use a data structure like tree with multiple child nodes. 为什么不只使用带有多个子节点的树之类的数据结构。

Suppose you need to store n dimensional array values, create a node pointing to the first dimension. 假设您需要存储n维数组值,创建一个指向第一个维的节点。 Say your first dimension length is 5 then you have 5 child nodes and if your 2nd dimension size is 10. Then for each of these 5 node you have 10 child nodes and so on.... 假设您的第一个维度长度为5,那么您有5个子节点,如果第二个维度大小为10。那么对于这5个节点中的每一个,您都有10个子节点,依此类推。

Some thing like, 就像是,

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

It will be easier to traverse through tree and is much cleaner. 遍历树更容易,也更干净。

First of all: Do you really need a jagged array? 首先:您真的需要锯齿状的阵列吗? Do you want to have some sort of sparse array? 您是否想要某种稀疏数组? Because otherwise, could you not just flatten your n-dimensional structure into a single, long array? 因为否则,您是否不仅可以将n维结构展平为单个长数组? That would not just lead to much simpler code, but most likely also be more efficient. 这不仅会导致代码简单得多,而且更有可能更有效。

That being said: It can be done for sure. 话虽如此:可以肯定地做到。 For example, just use a recursive template and rely on overloading to peel off levels of indirection until you get to the bottom: 例如,仅使用递归模板并依靠重载来剥离间接级别,直到到达最底端为止:

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);
}

You don't even need to explicitly specify the number of indirections n , since that number is implicitly given by the pointer type. 您甚至不需要显式指定间接数n ,因为该数目由指针类型隐式给出。

You can do basically the same trick to allocate/deallocate the array too: 您也可以执行基本相同的技巧来分配/取消分配数组:

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;
    }
};

Just this way around, you need partial specialization since the approach using overloading only works when the type can be inferred from a parameter. 就这样,您需要部分专业化,因为使用重载的方法仅在可以从参数推断类型时才有效。 Since functions cannot be partially specialized, you have to wrap it in a class template like that. 由于函数不能部分地专门化,因此必须将其包装在这样的类模板中。 Usage: 用法:

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);

Hope I didn't overlook anything; 希望我没有忽略任何事情; having this many indirections out in the open can get massively confusing real quick, which is why I strongly advise against ever doing this in real code unless absolutely unavoidable. 在公开场合公开如此众多的间接指令可能会使真正的快速操作造成极大的混乱,这就是为什么我强烈建议不要在实际代码中进行此操作,除非绝对不可避免。 Also this raw usage of new all over the place is anything but great. 同样,整个地方对new事物的原始使用都很棒。 Ideally, you'd be using, eg, std::unique_ptr . 理想情况下,您将使用例如std::unique_ptr Or, better yet, just nested std::vectors as suggested in the comments… 或者,更好的是,按照注释中的建议嵌套std::vectors

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM