The programmer cannot predict the number of objects to run computations at compile time. Knowing the exact number of objects in advance is rare, in fact. There are two primary exceptions:
- The domain itself has hard limits in place. For example, Chess is played on an 8 x 8 board with 16 pieces per player, so a program for playing chess can avoid dynamic allocation for storing the state of the board. However, the number of moves during the game is not known in advance, so dynamic memory would be required to provide a full game log.
- The designer chooses an arbitrary limitation on some aspect of the program. This can be for a number of reasons, including not wanting to design a flexible UI that can cope with arbitrary amounts of data (thus avoiding complex workflows like search, sort and paging) or to achieve soft real time performance goals( in a game context this could be trying to ensure that no frame takes more than 16.6 milliseconds).
Another is the behaviour of the object cannot be precisely determined at compile time. Most object oriented languages implement polymorphism by allocating a dynamic amount of memory, and returning some kind of reference to this memory. Other parts of the code might take a more generic reference, e.g. a pointer to a super class in C++, and without knowing the exact size or layout of the object it can be made use of. Some simple games can be implemented such that every game object inherits from a very simple base class with a virtual function for updating itself (e.g. Asteroids). Most people find that this approach typically doesn't scale well once the number of object types starts to grow.
Finally, a programmer may be forced to use dynamic memory because the language or library they are using make use of it. In particular, it is common in C APIs not to expose the definition of a data structure, which provides maximum freedom for the library implementor when making changes. For example, the Simple Directmedia Library (SDL) is a C API which does this. Some of the API calls wouldn't necessarily require dynamic amounts of memory, but by hiding the details the library implementation can change the size of it's data structures without changing the public API. It also makes the API consistent, as now there is a common pattern for interacting with all parts of the API.