Try this code:
#include <iostream>
#include <type_traits>
#include <cassert>
struct A{
A() {
std::cout<<"Called A() for "<<std::hex<<this<<'\n';
}
};
struct B {
A arr[10];
B() {
std::cout<<"Called B() for "<<std::hex<<this<<'\n';
}
};
int main() {
B* ptr = new B;
static_assert(std::is_standard_layout<B>::value); //Sanity check for this example's case
std::cout<<"Got ptr = "<<std::hex<<ptr<<std::dec<<" + sizeof(B) = "<<sizeof(B)<<'\n';
delete ptr;
return 0;
}
Output is:
Called A() for 0x10d4eb0
Called A() for 0x10d4eb1
Called A() for 0x10d4eb2
Called A() for 0x10d4eb3
Called A() for 0x10d4eb4
Called A() for 0x10d4eb5
Called A() for 0x10d4eb6
Called A() for 0x10d4eb7
Called A() for 0x10d4eb8
Called A() for 0x10d4eb9
Called B() for 0x10d4eb0
Got ptr = 0x10d4eb0 + sizeof(B) = 10
If you see the code and the corresponding output, you can correlate that the object ptr of type B is allocated on the heap at 0x10d4eb0 and it has a size of 10 (corresponding to 10 bytes, 1 byte each for the object A). So the memory address from 0x10d4eb0 till 0x10d4eb9 is all on the heap. And if you see the address of the objects of A, they all fall in this address range. Hence, the objects of A do lie in the heap memory area.
Now coming to how to handle arr, one needs to call delete/delete[], as the case may be, only on objects that have been allocated using new/new[]. Since that's not the case for arr, one doesn't need to call delete[] on it.