It sounds like you have a bad textbook.
A a practicable matter, every new implementation adds overhead or uses functions that add overhead. That overhead could be 4, 8, 16, whatever bytes. To say it's 4 is incorrect.
Invariably, overhead is added in front/below the memory returned by new. However, many allocators also add memory at the end that is used to check for overruns.
Assuming that the overhead is 4 bytes (and int is 4 bytes):
A* a = new A[10];
unsigned int *overhead = reinterpret_cast<int*>(&a[-4]) ;
In your case
int main()
{
A* a = new A[10];
A* b = a + 3;
delete[] b; // 1
delete[] a; // 2
}
delete 1, attempts to delete a block not allocated by new. Some new implementations could catch this.
delete 2, attempts to delete after the heap has been corrupted by 1.