In general an object can be created explicitly for example an application may create Loggers, Appenders and Layouts during creation of a QApplication object. But they can also be automatically created by the package on startup using a PropertyConfigurator configuration file. Objects may also be created the one way and then used the other. Object may be used by multiple other objects. A Layout for example may be used by multiple Appenders. Objects are also created from multiple threads. The creation may happen during static initialisation and the deletion during static de-initialization.
The parent child model used by QObject cannot be used to handle this. It cannot automatically delete an object that is used by multiple others as for example an Appender used by multiple Loggers. In addition to this QObjects and their children must reside in the same thread. This would either mean to impose restriction on how objects can be created or to move objects to a specific thread.
To allow an automatic deletion of not required objects the package implements reference counting for Appenders, Layouts and Filters. The reference counting is implemented in LogObject, which is used as a common base class. The reference count can be explicitly changed using the methods retain() and release(). Alternatively an auto pointer is available LogObjectPtr, which is used throughout the package.
The reference counting mechanism will test, if an object has a QObject parent object set. If a parent is set, the object will not be deleted, if the reference count reaches 0. This allows to mix the reference counted paradigm with the QObject parent child one.
The following example configures a logger and uses reference counting to manage the ownership of objects.
// Create layout TTCCLayout *p_layout = new TTCCLayout(); // Create appender ConsoleAppender *p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET); p_appender->activateOptions(); // Get logger Logger *p_logger = Logger::logger("MyClass"); p_logger->addAppender(p_appender); // ... // Remove appender from Logger p_logger->removeAllAppenders(); // p_appender and p_layout are deleted here
The following example configures a logger and uses QObject ownership of objects.
QObject *p_parent = new MyObject; // Create objects ConsoleAppender *p_appender = new ConsoleAppender(p_parent); TTCCLayout *p_layout = new TTCCLayout(p_appender); // Configure appender p_appender->setTarget(ConsoleAppender::STDOUT_TARGET); p_appender->setLayout(p_layout); p_appender->activateOptions(); // Get logger Logger *p_logger = Logger::logger("MyClass"); p_logger->addAppender(p_appender); // ... // Remove appender from Logger p_logger->removeAllAppenders(); delete p_parent; // p_appender and p_layout are deleted here
The following example shows how to use objects created on the stack.
{ // Create layout TTCCLayout layout; layout.retain(); // Create appender ConsoleAppender appender(&layout, ConsoleAppender::STDOUT_TARGET); appender.retain(); appender.activateOptions(); // Get logger Logger *p_logger = Logger::logger("MyClass"); p_logger->addAppender(&appender); // ... // Remove appender from Logger p_logger->removeAllAppenders(); // Without retain() program crashes here } // p_appender and p_layout are deleted here