diff -r 48780e181b38 -r 578be2adaf3e Symbian3/PDK/Source/GUID-F686965A-13E5-5C0A-AED1-55EC91C79433.dita --- a/Symbian3/PDK/Source/GUID-F686965A-13E5-5C0A-AED1-55EC91C79433.dita Tue Jul 20 12:00:49 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-F686965A-13E5-5C0A-AED1-55EC91C79433.dita Fri Aug 13 16:47:46 2010 +0100 @@ -1,95 +1,95 @@ - - - - - -Restrictions -on the use of leaves and TRAPs in destructorsOutlines the restrictions on the use of leaves and TRAPs in destructors. -

You cannot use TRAP (and TRAPD) -and User::Leave() in a destructor, nor in any function -that a destructor might call, for objects that have been placed onto the call -stack. TRAP and User::Leave() are implemented -in terms of C++ Try, Catch and Throw. This means that if an exception occurs, -the call stack is "unwound". In doing this, the destructors of objects on -the call stack are called. If any of these destructors subsequently throw -an exception, this is termed a nested exception. While a nested exception -is supported on the emulator (WINS), it is not supported on other hardware, -and there is no guarantee that the thread will terminate cleanly.

-

Symbian coding standards state that objects placed onto the call stack -should not have non-trivial destructors. By convention, such classes are identified -by names having an initial T or R. This means that such destructors should -not leave.

-

The following code fragment shows the kind of code that is not safe to -use:

-void f() - { - TBar bar; - // Function processing. - ... - // The bar object on the call stack is automatically destroyed - // at function termination. - } - -TBar::~TBar() - { - // The destructor calls a function that can leave. - // This is not permitted here. - doCleanUpL(); - } -

You can use TRAP (and TRAPD) -and User::Leave() in a destructor and in any function that -a destructor might call, for heap-based objects, i.e. objects that are destroyed -by the cleanup stack. However, while this is permissible, it is not recommended -practice.

-

Such objects are instances of classes derived from CBase, -and by convention such classes are identified by names having have an initial -C.

-

In principle, a destructor should never fail. If a destructor can leave, -or a function called by the destructor can leave, it suggests that the code -has been poorly architected. It also implies that part of the destruction -process might fail, potentially leading to memory or handle leaks.

-

One possible approach to avoid using functions that can leave within a -destructor is to have what might be referred to as ‘two-phase destruction’ -where some form of ShutdownL function is called prior to -deleting the object. If there are concerns about introducing additional complexities -in API-usage (and greater risk), suitable guards can be introduced. One method -might be to store the current state of the object internally and then use -an ASSERT to check this in the destructor. This would ensure that any usage -errors are discovered by very simple run time testing.

-

The following code fragment shows an example of two-phase destruction.

-// Here, the shutdown function is a member of the class CMyClass, -// and performs destruction activity that can leave. - -class CMyClass : public CBase - { -public : - IMPORT_C ~CMyClass(); - IMPORT_C void ShutdownL(); - ... -private : - TBool iStateActive - ... - } - -EXPORT_C void CMyClass::ShutdownL() - { - if (iStateActive == ETrue) - { - // Some destruction activity that can leave. - iStateActive = EFalse; - } - } - -EXPORT_C CMyClass::~CMyClass() - { - // Assert to ensure that ShutdownL() has already been called. - ASSERT(iStateActive == EFalse); - } - + + + + + +Restrictions +on the use of leaves and TRAPs in destructorsOutlines the restrictions on the use of leaves and TRAPs in destructors. +

You cannot use TRAP (and TRAPD) +and User::Leave() in a destructor, nor in any function +that a destructor might call, for objects that have been placed onto the call +stack. TRAP and User::Leave() are implemented +in terms of C++ Try, Catch and Throw. This means that if an exception occurs, +the call stack is "unwound". In doing this, the destructors of objects on +the call stack are called. If any of these destructors subsequently throw +an exception, this is termed a nested exception. While a nested exception +is supported on the emulator (WINS), it is not supported on other hardware, +and there is no guarantee that the thread will terminate cleanly.

+

Symbian coding standards state that objects placed onto the call stack +should not have non-trivial destructors. By convention, such classes are identified +by names having an initial T or R. This means that such destructors should +not leave.

+

The following code fragment shows the kind of code that is not safe to +use:

+void f() + { + TBar bar; + // Function processing. + ... + // The bar object on the call stack is automatically destroyed + // at function termination. + } + +TBar::~TBar() + { + // The destructor calls a function that can leave. + // This is not permitted here. + doCleanUpL(); + } +

You can use TRAP (and TRAPD) +and User::Leave() in a destructor and in any function that +a destructor might call, for heap-based objects, i.e. objects that are destroyed +by the cleanup stack. However, while this is permissible, it is not recommended +practice.

+

Such objects are instances of classes derived from CBase, +and by convention such classes are identified by names having have an initial +C.

+

In principle, a destructor should never fail. If a destructor can leave, +or a function called by the destructor can leave, it suggests that the code +has been poorly architected. It also implies that part of the destruction +process might fail, potentially leading to memory or handle leaks.

+

One possible approach to avoid using functions that can leave within a +destructor is to have what might be referred to as ‘two-phase destruction’ +where some form of ShutdownL function is called prior to +deleting the object. If there are concerns about introducing additional complexities +in API-usage (and greater risk), suitable guards can be introduced. One method +might be to store the current state of the object internally and then use +an ASSERT to check this in the destructor. This would ensure that any usage +errors are discovered by very simple run time testing.

+

The following code fragment shows an example of two-phase destruction.

+// Here, the shutdown function is a member of the class CMyClass, +// and performs destruction activity that can leave. + +class CMyClass : public CBase + { +public : + IMPORT_C ~CMyClass(); + IMPORT_C void ShutdownL(); + ... +private : + TBool iStateActive + ... + } + +EXPORT_C void CMyClass::ShutdownL() + { + if (iStateActive == ETrue) + { + // Some destruction activity that can leave. + iStateActive = EFalse; + } + } + +EXPORT_C CMyClass::~CMyClass() + { + // Assert to ensure that ShutdownL() has already been called. + ASSERT(iStateActive == EFalse); + } +
\ No newline at end of file