Let's look at the (logical) memory layout of vector:
[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
*[elements:size*sizeof(element) bytes] << one contiguous memory (pointer to heap)
With a vector of vectors it looks like this:
[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
* [
[Vector:0]
[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
*[elements:size*sizeof(element) bytes] << pointer to contiguous memory for elements
[Vector:1]
[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
*[elements:size*sizeof(element) bytes]
[Vector:2]
[size:4/8 bytes]
[capacity:4/8 bytes]
[other datamembers:n bytes]
*[elements:size*sizeof(element) bytes]
...
...
] << contiguous memory of vectors
This means that a vector has a pointer to contiguous memory storing vectors, each of which stores their elements pointing to another heap with contiguous memory storing the elements.
But if you managed to create an allocator to be used by the vector, such that it would allocate blocks of memory that are contiguous, you'd still face issues where if one of the nested vectors gets removed, the memory is no longer contiguous. Not to mention the situation of having the nested vector having different sizes.
Depending on your use-case you can either use the customer contiguous block memory allocator for a vector of vector, or just do it the old way of manually allocating and deallocating one contiguous block of memory.