Comparison between leave mechanism and C ++ exception Mechanism

Source: Internet
Author: User

Link: http://developer.symbian.org/wiki/index.php/A_Comparison_of_Leaves_and_Exceptions

 

In earlier versions of the Symbian system, C ++ had no exception mechanism, so Symbian developed its own leave and trap systems. In Symbian OS V9, the exception mechanism is added, and the leave/trap architecture is implemented again.

This article discusses the motivations for implementing leave and trap with the c ++ exception mechanism, and also describes some related technical problems and restrictions.

Index

1. Motivation

2. Implementation Details

3. Use of leave and trap

4. Standard C ++ exception

5. Best practices

6. Portability details

7. FAQs

 

Motivation

Trap is implemented using the C ++ exception Mechanism for the following reasons:

  • The legacy Symbian trap consumes CPU resources even if the Code does not have leave, while the exception mechanism significantly saves the CPU.
  • Trap is incompatible with standard C ++ exceptions. This means that the standard C ++ code and the Symbian-style C ++ Code cannot coexist. If an exception mechanism is used to implement trap, it is possible for the two to coexist in one program (careful encoding is required ).
  • C ++ exception is an industrial standard, and Symbian is logically aligned with it.
  • The C ++ exception mechanism has been standardized and has more extensive and better local hardware support (such as Eabi ). This makes C ++ exceptions faster than trap and easier to transplant.

Implementation Details

According to the requirements of the Symbian system, the exception mechanism must ensure that the out of memory (OOM) behavior is definite and safe. This leads to a large limit (relative to the standard exception mechanism ):Nested exceptions are not allowed.
.

When an exception object is thrown, the system must allocate memory to generate the object. The implementation of the Symbian system reserves enough memory to ensure that this object can be created successfully (the reserved memory is used to cope with OOM ). However, in case of nested exceptions, the memory reserved by the system may be insufficient. if the system is already in the OOM state, the system will not have more available memory to create exception objects.

On an arm device, if a nested exception occurs, Symbian directly calls abort (). This situation occurs most often when the stack is expanded (that is, an exception has occurred), and an exception is thrown in a destructor.

Note:
Nested exceptions are allowed on wins because the WINS exception mechanism is implemented based on Win32 structured exception handling (seh. Therefore, the code running normally on the simulator may be abnormal on the real machine.

 

Leave
And
Trap
Usage

The steps for implementing user: Leave () in Symbian OS V9 are as follows:

1. Call User: Leave ()

2. Expand the "cleanup stack" in Symbian (the cleanup stack is unwound)

3. Create an xleaveexception object and throw it. If there is enough space on the stack, the memory of the exception object is allocated to the stack; otherwise, the object is created using the stack memory reserved by the system. This reserved memory ensures that the exception object can still be created successfully in the OOM state.

4. Normal stack expansion process (that is, the stack expansion step in Standard C ++ Exception Handling)

5. The Catch Block is executed.

Here are some notes:

Step 2: destroy all heap-based objects in the stack.

In this step, the leave-related exceptions have not yet occurred (because only the stack is being cleaned up, and no exception object is generated ). In this process, throwing an exception is not dangerous, because it is impossible to create an exception nesting. Before the exception object is generated in the next step, the exception generated by the object destructor on the stack will be processed (this exception needs to be caught in the destructor ).

Step 2: Destroy stack-based Objects

In this step, the exception object related to leave has been created. If an exception is thrown during this process, the system must support exception nesting because an exception object has been thrown (created in step 1), which is allowed on wins, however, it is explicitly prohibited on arm.

Step 2: Execute the exception recovery code (Catch Block)

In this step, the exception handling is completed, and the catch block contains only common code. It is safe to throw an exception during this process.

Therefore, it is safe to use trap in their destructor for objects allocated on the stack (destroyed by the stack cleanup), but not for objects allocated on the stack. The cbase subclass allocates memory on the heap, so it is safe to use trap in the cbase subclass destructor. Any object that is destructed during standard stack expansion (step 1 above) is insecure if its destructor uses trap or leave. It is impossible to throw an exception safely in step 1.

 

Use Standard
C ++
Exception

Instead of the leave/trap framework, we can directly use standard C ++ exception handling. In this case, the constraints become clear.

Stack cleanup is a unique mechanism of Symbian and is not used in standard C ++. Therefore, when only standard C ++ is used, you only need to consider the objects allocated on the stack. The constraints here are the same: it is unsafe to use exceptions in the destructor of objects allocated on the stack.

 

Best practices

As described above, trap can be used in the subclass destructor of cbase. However, we recommend that you keep the Destructor concise and avoid using leave-related code, regardless of the allocated objects on the stack or the objects on the stack. Using the leave mechanism in the Destructor implies that a step in the Destructor may fail, which may lead to potential memory or handle leakage. It is wise to avoid using the leave mechanism (that is, not the function ending with L) for functions called in the destructor, rather than simply returning tint.

One way to avoid using the end function of L in the Destructor is to use the "two-stage destructor". For example, you can call a method like shutdownl () before deleting an object, put all functions that may be leave in the shutdownl.

If you think the above Code brings extra complexity, you can use "guards": use an internal variable to store the object state, and then use assert in the destructor to check this state, in this way, a simple method can be used to ensure that a usage error (usage-errors) is detected during the runtime ). Consider the following example:

// Shutdown function which performs any destruction which may leave. <br/> class cobject: shutdownl () <br/> {<br/> If (istateactive = etrue) <br/>{< br/> // some destruction which may leave. <br/> istateactive = efalse; <br/>}< br/> cobject ::~ Cobject () <br/>{< br/> // assert to ensure that shutdownl has already been called. <br/> assert (istateactive = efalse); <br/>}

If the function ending with l must be called in the destructor, trap must be used to process the function. Otherwise, leave in the Destructor will terminate the entire program.

 

Portability details

Using the exception mechanism of c ++ to implement leave and trap brings some additional restrictions in use. These restrictions only affect the destructor. The specific rules are as follows:

  • Class Object destroyed during stack expansion, in its destructorCertainly not
    Use leave and trap.
  • Class Object destroyed by the cleaned stack (such as the cbase subclass), in its destructorAvailable
    Leave and trap. Of course, this is not recommended.
  • DestructorCertainly not
    Leave or throw an exception. The leave in the Destructor must be handled by trap, and the exceptions in the Destructor must be caught.

These rules are applied to the Destructor and the functions called within the destructor.

 

FAQs

Q: If the class object is allocated to the stack, you can use trap in the class destructor.
Is the stack cleaned up?

A: Yes.

 

Q: Can I use Delete directly?
What about it?

A: Not always. In most cases, it is okay to use Delete directly. The only danger is that the object is deleted when the stack is expanded, and trap is used in the destructor of the object. This is because there is already an active exception object, and trap may cause subsequent exceptions (that is, nested exceptions ).

Consider the following three examples:

 

Class cfoo: Public cbase <br/>{< br/> ~ Cfoo () <br/>{< br/> trap (ERR,/* Leaving Code */); <br/>}< br/>}

 

1. Calling Delete outside the Destructor is always safe.

Class canother <br/>{< br/> void cmiscfunction () <br/>{< br/> cfoo Foo = new (eleave) cfoo (); <br/> cleanupclosepushl (FOO); <br/> foo-> constructl (); <br/>... <br/> Delete Foo; <br/> cleanupstack: Pop (FOO); <br/>}< br/>}

 

 

2. It is sometimes safe to call Delete in the destructor of objects allocated on a stack.

Class cbar: Public cbase <br/>{< br/> cbar (cbase * afoo): ifoo (afoo) <br/>{< br/>}< br/> ~ Cbar () <br/>{< br/> Delete ifoo; <br/>}< br/> cfoo * ifoo; <br/>}< br/>

This code is safe only when the cbar destruction process is completed by clearing the stack. This is because no exception is thrown during the process of using the clear stack to destroy objects.

 

 

3. It is insecure to call Delete in the destructor of an object (such as a class t) allocated on a stack.

Class tyetanother <br/>{< br/> tyetanother (cbase * afoo): ifoo (afoo) <br/>{}< br/> ~ Tyetanother () <br/>{< br/> Delete ifoo; <br/>}< br/> cfoo * ifoo; <br/>}

In this example, tyetanother is designed to automatically delete the object ifoo allocated on the stack. However, this is insecure in any Symbian system.

Before the exception mechanism is introduced to implement leave, the objects created on the stack are simply released by the memory and will not call the destructor. Therefore, ifoo will not be deleted.

After leave is implemented with exceptions, the destructor of the objects created on the stack will be called during stack expansion. However, before the delete operation, an exception object may be thrown, resulting in nested exceptions.

If you want to implement functions similar to the above, use the clear stack.

 

Q: according to the three rules in "portability details", the following code is safe, but is not recommended?

Cfoo ::~ Cfoo () <br/>{< br/>... <br/> trapd (ERR, imember-> disablel (); <br/>... <br/>}

 

A: Yes. If cfoo is a sub-class of cbase, the code is okay. The object is allocated to the stack and put into the cleanup stack.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.