Object ownership

In difference to the JAVA Log4j package Log4Qt must manage ownership and lifetime of the objects used. This is non trivial as objects are created and used in different ways.

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

Generated on Sun Mar 1 16:40:45 2009 for Log4Qt by  doxygen 1.5.6