-
Notifications
You must be signed in to change notification settings - Fork 5
Concepts
The main goals of Inanity design are:
- Safety. No memory leaks, no dangling pointers, no hidden errors.
- Performance.
- Simplicity. Solve small problems.
- Abstraction. Provide abstractions to make general solutions possible.
In a few words, Inanity is an attempt to make a framework balancing between C++'s performance and C#'s safety.
All Inanity code is located in the C++ namespace Inanity and sub-namespaces, such as Inanity::Graphics or Inanity::Crypto. No code is located in the default namespace.
All header files #include a minimal set of required headers. Header files use forward declarations whenever possible. Full set of headers are included only in .cpp files. Headers which define templates are sometimes additionally separated into .hpp and .ipp files, with template declarations in .hpp, and template definitions in .ipp. This method allows for mutual reuse templates in different files.
Almost all non-POD types in Inanity are derived from Inanity::Object class. That allows storing pointers to objects of these classes in the smart pointer class Inanity::ptr<T>. Most methods in Inanity accept and return ptr's, and not plain C++ pointers.
ptr's are not capable of resolving circular references. There is no garbage collection, and objects are deleted whenever they lose the last reference.
Inanity::Object redefines operator new, so all Object's are created in the special managed heap. The heap is responsible for objects allocation and memory leaks detection (when appropriate mode is on).
The recommended way of creation new Object's is the NEW macro. The NEW macro stores useful runtime information about allocations in debug configuration which helps with resolving leaks and circular references. In release configuration the NEW macro turns into regular operator new. You can use the regular new too, but you won't get debugging information.
Note that some classes allow allocation on stack for performance reasons, but you should be careful - pointers of such instances should not be stored in ptr's.
Also note that although Object::operator new is thread safe, Object's and ptr's themselves are not (except when a class explicitly states thread safety). As usual, you have to use synchronization primitives in order to operate them from more than one thread.
Inanity are written with RAII idiom in mind. All objects are initialized when they are created, and are uninitialized when they are destroyed. There is no such thing as "uninitialized" object (except explicitly stated rare cases, when object deinitialization can happen without our permission, such as network sockets). So, for example, the disk file class has no method Close: to close the file just release all ptr references to it.
Following RAII principle allows to write exception-safe code. And Inanity does use exceptions for error handling.
Methods (and classes too) in Inanity tend to be simple and do only one thing (but do it well). By agreement, if a method returns ptr of some object, it always return a valid object, and never the null pointer. If a method is unable to return valid object, it throws an exception. Such rule allows us to program without a lot of checks, and chain method calls safely. Most of the code assumes that errors are rare and exceptional, and if error has been raised, performance won't longer matter.
There are some exceptions of no-null rule. Firstly, getter methods are allowed to return null pointers when it is reasonable. Secondly, methods which name begins with "Try" might return null object in case of failure. (They might throw an exception either in case of serious unexpected problem). "Try" methods are here for performance reasons, and exists in cases where errors are frequent and expected.
There are macros for throwing exceptions. The THROW macro throws an exception with description string. The THROW_SECONDARY throws an exception with description string and pointer to inner exception. Most methods in Inanity catches exceptions from subcalls and wraps them to their secondary exceptions to form so-called exception stack. That stack can be catched in topmost level and displayed to user or sent to the developer for investigation.
All Inanity code throws only Exception* type. When catching it, you should place it into ptr in order to free it correctly.