views:

334

answers:

4

Just flicking through one of my favourite books (Ellen Ullman's The Bug) and there is a small bit where one programmer confronts another over three levels of indirection:

***object_array = ***winarray;

I get the idea of double indirection - a way of passing a pointer into a function, and allowing it to point to an object created within the function.

But have you come across any reason to use three (or more) levels of indirection?

+3  A: 

Sure
4 dimensional arrays.
It doesn't take too much for an application for such an array either. Say some sort of lookup table. I've had lookup tables of 8 and more dimensions.

shoosh
+3  A: 

As David Wheele said: "Any problem in computer science can be solved with another layer of indirection." You have almost certainly used three layers of indirection with a line like this:

int x = 3;

After all, the chip is indirecting memory access through two layers of L1 and L2 cache. And the OS is indirecting the memory access via virtual memory pages. And your C# compiler is indirecting the memory access via objects in a virtual machine. Sure, it doesn't come with a long line of asterixes, but that's because all of these indirections are abstracted with things liks a machine, an OS or a compiler.

mcherm
+1  A: 

You're possibly running at 3 or more levels right now. Could be jQuery on javascript in a browser running in Windows on a Mac (or in a VM) via Remote Access running in ....

Or, from another perspective closer to your question's context, 3 levels is the most common artifact we have.

What's a pointer to a control in a container in a Window?

le dorfier
+2  A: 

No, I've never actually seen or used it (as far as I can recall, and at least not without sensible typedefs to make it less fubar), but I can contrive an example of what might be a [questionably] valid use:

struct Foo{
    struct greater{
        bool operator()(Foo const *a, Foo const *b) const{
            return a->place > b->place ||
                   a->place == b->place && a->holder > b->holder;
        }
    };

    int place;
    int holder;
};

template<typename T, typename Comparer>
void Sort(T const *unorderedList, int count, T const ***orderedList, Comparer &cmp);

void UseOrderedList(Foo const **orderedList, int count);

int main(){
    Foo list[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
    Foo const **orderedList;

    Sort(list, sizeof list / sizeof *list, &orderedList, Foo::greater());
    UseOrderedList(orderedList, sizeof list / sizeof *list);
    delete[] orderedList;
    return 0;
}

void UseOrderedList(Foo const **orderedList, int count){/*...*/}

template<typename T, typename Comparer>
void Sort(T const *unorderedList, int count, T const ***orderedList, Comparer &cmp){
    /*
     * The result array stores pointers to the items in the original array.
     * This way, the original array is unmodified, and the result array
     * doesn't create duplicate items.  This makes sense if the objects
     * are large and copying them would be slow (another argument against
     * in-place sorting), or if duplicating them violates some design
     * principle.
     */
    *orderedList = new const T*[count];

    for(int i = 0; i < count; i++)
        (*orderedList)[i] = unorderedList + i;

    std::sort(*orderedList, &(*orderedList)[count], cmp);
}

I wouldn't actually do what I've done here. It's just an example of how you could end up with three pointer levels. I can't imagine you running into this kind of scenario very often, though.

P Daddy