Your question is probably best answered by an explanation of what void means.
void basically denotes the absence of a type. As a consequence of this, you cannot tell the compiler to create an object of type void, e.g. with the following statements:
The meaning of these expressions is roughly the following: "create something", or "create an array of somethings" respectively. This is clearly not a precise enough statement for the compiler.
void* (pointer to void) however is permitted because pointers are fundamentally always the same thing to the compiler: a memory address of another object. You can think of a pointer as some kind of arrow pointing to something. If you're working with a pointer, the compiler sees that arrow, and not the actual thing it points at. Therefore the compiler doesn't care that the "target type" is void.
The consequence of this, however, is that you cannot dereference a void* (pointer to void), because then you make the compiler effectively look at the pointed-to thing, which would be a void value, which doesn't make any sense to the compiler.
Summary:
1) You cannot create an array of type void, as in new void[...].
2) You can create a pointer to void (void*), or even a pointer to a pointer to void* (void**).
3) You cannot dereference a void* pointer (but you can dereference a void** pointer).
Conclusions:
4) You can create an int* array and let a void* refer to it:
int** m;
// ... (create the dangling array as in the OP's code and let m point to it)
void* v = (void*)m;
(See the comments below on why a void* is used here instead of void**!)
5) Because of statement #3, all you can reasonably do with such a pointer is pass it around, but you cannot work on the array's actual content. In order to do this, you need to type-cast it back to the correct data type:
int **m2 = (int**)v;