The functions for creating objects, allocating the memory that the objects require, configuring the objects appropriately, and running cleanup code after the objects finish their work, are called the Setup API.
Functions in the Pia Setup API have names like Initialize() / Finalize(), BeginSetup() / EndSetup(), CreateInstance() / DestroyInstance(), and Startup() / Cleanup(). They have uniform conventions for the order in which they must be called.
To initialize a set of objects in a Pia module, you must first call the Initialize() function at the top level of the namespace for the module. Next, call the BeginSetup() function, and then either the singleton's create function or the Initialize() function of the class, followed by the EndSetup() function.
Calling the create function of a singleton or the Initialize() function of a class may cause the Pia library to allocate memory. You must make such calls between calls to the BeginSetup() and EndSetup() functions because of the design of the memory management system in the Pia library.
Some Pia classes have a Startup() member function. The Startup() function puts the object in a usable state. For example, it configures the properties of the object.
Calling a Startup() function never causes the Pia library to allocate memory. The Startup() functions are designed to be called after the corresponding object or module has been initialized.
Some Pia classes have a Cleanup() member function. The Cleanup() and Startup() functions form a pair. The Cleanup() function makes the object unusable by, for example, setting the properties of the object to invalid values.
Calling a Cleanup() function never causes the Pia library to free memory.
Finalization in the Pia library is accomplished by functions such as Finalize() and DestroyInstance(). These functions form pairs with the Initialize() and CreateInstance() functions, respectively.
Call these finalization functions in the opposite order from the initialization functions.
The following code sample illustrates the initialization, startup, cleanup, and finalization processing chain.
// Initialize the module_y module.
{ nn::pia::module_x::Initialize(); nn::pia::module_x::BeginSetup(); // Generally, creating a singleton by calling the CreateInstance() function allocates memory internally. // You must call the CreateInstance() function between calls to the BeginSetup() and EndSetup() functions. nn::pia::module_x::ClassA::CreateInstance(); nn::pia::module_x::ClassB::CreateInstance(); nn::pia::module_x::EndSetup(); } // Initialize the module_y module. { nn::pia::module_y::Initialize(); nn::pia::module_y::BeginSetup(); nn::pia::module_y::ClassC::CreateInstance(); nn::pia::module_y::ClassD::CreateInstance(); // Some Pia classes require that you call an Initialize() member function. // The Initialize() function can allocate memory in Pia, // so call it between the BeginSetup() function and the EndSetup() function. nn::pia::module_y::ClassD::GetInstance()->Initialize(); nn::pia::module_y::EndSetup(); } // Call the Startup() function, and make the ClassC object available for use. nn::pia::module_y::ClassC::GetInstance()->Startup(); // The main loop in the game. while(1) { ... } // Call the Cleanup() function, which makes the ClassC object unavailable for use. nn::pia::module_y::ClassC::GetInstance()->Cleanup(); // Finalize the module_y module. Call the functions in the opposite order from initialization. { nn::pia::module_y::ClassD::GetInstance()->Finalize(); nn::pia::module_y::ClassD::DestroyInstance(); nn::pia::module_y::ClassC::DestroyInstance(); nn::pia::module_y::Finalize(); } // Finalize module_x. Call the functions in the opposite order from initialization. { nn::pia::module_x::ClassB::DestroyInstance(); nn::pia::module_x::ClassA::DestroyInstance(); nn::pia::module_x::Finalize(); } |
Initialize the Pia modules in the following order.
1. common
2. inet or local
3. transport
4. sync, chat, clone, or reckoning
5. session
Finalize Pia modules in the reverse order.
Initializing and setting up new modules after finalizing previously initialized modules is prohibited. For example, after initializing and setting up the common, module_x, and module_y modules in order, you cannot finalize module_x and then initialize and set up a new module_z.
You must call both BeginSetup() and EndSetup() for each module. There is no support for operations if you have forgotten to call EndSetup().
Also, after finalizing a Pia module, do not call non-finalizer APIs in other Pia modules. Doing so could cause your program to crash because the Pia library may try to access an object that was freed by finalization.
Finalize all Pia modules together after all processing is complete. (See the @ref: Pia Process Classification Terminology.)
// This is an example of incorrect processing.
// You must not call the Dispatch() function of the common module after calling Session::DestroyInstance() because this latter function finalizes the session module. // Failing to follow the correct order in your program could lead to access violations and // crashes. nn::pia::session::Session::DestroyInstance(); . . . nn::pia::common::Scheduler::GetInstance()->Dispatch(); |
As described previously, Pia modules and classes provide Cleanup() and Finalize() functions for cleaning up or finalizing objects.
These functions always succeed, even if the corresponding Startup() or Initialize() function has not been called, or has been called but failed at the time the cleanup or finalization function was called.
This reduces the work required by the application developer to deal with failure during initialization in the finalization code.