There really isn’t any other way to do it. The compiler needs to know the size of every non-dynamically allocated instance of a type at compile time. If you are dynamically allocating memory, this cannot be known at compile time. So you can’t access the object directly through a variable when allocation is dynamic. The nice thing about pointers is that (on all systems on which I’ve worked) they are all the same size (usually 4 bytes on a 32 bit computer and 8 bytes on a 64 bit machine). So, the pointer variables will all be the same size regardless of the size of the item pointed to.
In other words, because the program cannot reserve space for an item itself because its size is not known at compile time, it needs to provide a uniform-sized mechanism for accessing these objects which are of varying size. A pointer’s size is the size of a memory address and a memory address can be used to access any item.
So … it’s kind of hard to imagine how else it could be done … Now, you don’t need to use raw pointers. You can use smart pointers instead to avoid some of the difficulties of using raw pointers.