An exception cannot be thrown in the destructor.

Source: Internet
Author: User

In terms of syntax, exceptions thrown by the Destructor are acceptable. c ++ does not prohibit exceptions caused by the destructor, but C ++ does not recommend this practice, it is dangerous to throw an exception from the destructor.

The Destructor may be called when the object ends its lifecycle normally, or when an exception occurs, it may be called when the function stack is cleaned up. In the previous case, exceptions are thrown without unexpected results and can be captured normally. In the latter case, an exception occurs in the function, causing the destructor of the local variable of the function to be called, and the Destructor throws an exception, the exception thrown by a local object should be captured by the function in which it is located. Now that an exception has occurred in the function, it cannot be captured. Therefore, the exception handling mechanism can only call terminate (). If you really have to throw an exception from the destructor, you should first check whether there are any exceptions that have not been processed. If not, the exception can be thrown normally.

When will the Destructor be called for execution?

For C ++ programmers, this problem is relatively simple. However, I suggest you repeat the knowledge of C ++ here, in addition, this will be helpful for further discussions and understandings. Let's take a look at a simple example! As follows:

[CPP]
View plaincopy

  1. Class mytest_base
  2. {
  3. Public:
  4. Virtual ~ Mytest_base ()
  5. {
  6. Cout <"destroy an object of the mytest_base type" <Endl;
  7. }
  8. };
  9. Void main ()
  10. {
  11. Try
  12. {
  13. // Construct an object. When the OBJ object leaves this scope, the Destructor will be executed.
  14. Mytest_base OBJ;
  15. }
  16. Catch (...)
  17. {
  18. Cout <"unknow exception" <Endl;
  19. }
  20. }

Compile and run the above program. The running result of the slave program indicates that the object's destructor has been executed, but when will it be executed? According to the C ++ standard, an object should be called and run when it leaves its scope. In fact, the C ++ compiler of each vendor also meets this requirement. Use VC for a test and verification !, The following lists the program fragments copied during debugging by the small sample program. Note that the OBJ object will be inserted by the compiler when it leaves the try block to call the object's destructor implicitly. As follows:


325: Try
326 :{
00401311 mov dword ptr [ebp-4], 0
327: // construct an object. When the OBJ object leaves this scope, the Destructor will be executed.
328: mytest_base OBJ;
00401318 Lea ECx, [OBJ]
0040131b call @ ILT + 40 (mytest_base: mytest_base) (0040102d)
329:
330:} // The Compiler inserts a piece of code to call the object's destructor implicitly.
00401320 Lea ECx, [OBJ]
00401323 call @ ILT + 15 (mytest_base ::~ Mytest_base) (00401014)
331: Catch (...)
00401328 JMP _ tryend $ _ main $1 (00401365)
332 :{
333: cout <"unknow exception" <Endl;
0040132a mov ESI, ESP
0040132c mov eax, [_ imp _? Endl @ STD @ yaaav? $ Basic_ostream @ du? $ Char_traits @ d @ STD @ 1 @ aav21 @ Z (0041610c)
00401331 push eax
00401332 mov EDI, ESP
00401334 push offset string "unknow exception" (0041401c)
00401339 mov ECx, dword ptr [_ imp _? Cout @ STD @ 3 V? $ Basic_ostream @ du? $ Char_traits @ d @ STD @ 1 @ A (00416124)
0040133f push ECx
00401340 call dword ptr [_ imp _?? 6std @ yaaav? $ Basic_ostream @ du? $ Char_traits @ d @ STD @ 0 @ aav10 @ PBD @ Z (004
00401346 add ESP, 8
00401349 cmp edi, ESP
0040134b call _ chkesp (004016b2)
00401350 mov ECx, eax
00401352 call dword ptr [_ imp _?? 6? $ Basic_ostream @ du? $ Char_traits @ d @ STD @ qaeaav01 @ p6aaav01 @ aav01
00401358 cmp esi, ESP
0040135a call _ chkesp (004016b2)
334 :}
0040135f mov eax, offset _ tryend $ _ main $1 (00401365)
00401364 RET
335 :}
Exceptions thrown in destructor
1. Check the example as follows:

[CPP]
View plaincopy

  1. Class mytest_base
  2. {
  3. Public:
  4. Virtual ~ Mytest_base ()
  5. {
  6. Cout <"start preparing to destroy an object of the mytest_base type" <Endl;
  7. // Note: An exception is thrown in the destructor.
  8. Throw STD: exception ("throwing an exception intentionally in the destructor, test! ");
  9. }
  10. Void func () Throw ()
  11. {
  12. Throw STD: exception ("intentionally throw an exception, test! ");
  13. }
  14. Void other (){}
  15. };
  16. Void main ()
  17. {
  18. Try
  19. {
  20. // Construct an object. When the OBJ object leaves this scope, the Destructor will be executed.
  21. Mytest_base OBJ;
  22. OBJ. Other ();
  23. }
  24. Catch (STD: exception E)
  25. {
  26. Cout <E. What () <Endl;
  27. }
  28. Catch (...)
  29. {
  30. Cout <"unknow exception" <Endl;
  31. }
  32. }

The running result is:
Start preparing to destroy an object of the mytest_base type.
Deliberately throw an exception in the Destructor and test it!

From the above program running results, there is nothing special. in the program, an object is first constructed. When the object leaves its scope, the Destructor is called, at this time, the Destructor throws an STD: exception type exception. Therefore, the catch (STD: exception e) block after the exception captures the exception and prints the Exception error message. This process seems to show that the exceptions in the Destructor are not very different from those in other places (such as in the object's member functions, except that destructor are called implicitly, this does not affect the exception handling mechanism! What are the differences? What about xuanjicang? Continue!

2. Make minor changes based on the above program. The program code is as follows:

[CPP]
View plaincopy

  1. Void main ()
  2. {
  3. Try
  4. {
  5. // Construct an object. When the OBJ object leaves this scope, the Destructor will be executed.
  6. Mytest_base OBJ;
  7. // The following statement is newly added
  8. // An exception will be thrown when this member function is called.
  9. OBJ. func ();
  10. OBJ. Other ();
  11. }
  12. Catch (STD: exception E)
  13. {
  14. Cout <E. What () <Endl;
  15. }
  16. Catch (...)
  17. {
  18. Cout <"unknow exception" <Endl;
  19. }
  20. }

Note: The current running result of the modified program: Unfortunately, the program crashes after printing a Statement on the console (if the program is a debug version, A program will be terminated. If it is a release version, the program will be terminated after the terminate () function is executed ). The result of running the debug version on the machine where the hero is aliyun is as follows:

Many of my friends may be confused about this result. Is it strange? Who is wrong! Isn't that a new code problem! (In fact, many programmers and friends have suffered too many such errors. For example, if a program runs well and functions are expanded later, the program will often crash. In fact, sometimes the program does not add much code during expansion, and the related programmers carefully check their added code to confirm that the code added later is indeed no problem! The owner may not think so. I think the program has been running quite well before. After you have modified the program, an error occurs. Isn't it a problem caused by the code you added? It's really a battle in the field of program development! In fact, there is no reason for such reasoning. objectively and fairly speaking, the program crash must be related to the module code added later! But the real bug may always exist in the original system, but it has never been induced to show it! Look! Ah Yu, the hero, has a question! Back to the question !)

So what is the problem? In fact, this is actually caused by exceptions thrown in the destructor, but this is even more surprising. The exceptions thrown in the Destructor are no problem! Didn't the previous example have been tested? Yes, but that is just an illusion. If you want to make your system reliable, secure, and run for a long period of time without a fault, you must ensure at least one point in program exception handling design and coding, that is, the Destructor will not always throw an exception, and this is also stated in the C ++ standard, but it does not elaborate on the real reasons. So why? Why does the C ++ standard stipulate that exceptions cannot be thrown in the Destructor? This is indeed a very difficult issue, and it is difficult to clarify it very clearly. However, the hero, a Yu, is willing to discuss his own understanding and thoughts on this issue, hoping to reach a consensus on understanding with programmers and friends.

The C ++ Exception Handling model is designed for the c ++ language. Furthermore, it actually serves the object-oriented language, in the previous article, we repeatedly complained that the biggest feature and advantage of the C ++ Exception Handling model is that it provides the most powerful seamless support for Object-Oriented in C ++. Okay. That's all! If the object encounters an exception during running, the C ++ Exception Handling model has the responsibility to clear invalid objects due to exceptions (that is, the objects exceed their original scope ), and release the original resources of the object. This is to call the destructor of these objects to release the resource. Therefore, in this sense, the Destructor has become part of exception handling. I wonder whether you understand the true internal meaning of this passage, that is, the above discussion about the C ++ Exception Handling model. It actually has a premise assumption that the Destructor should not throw any more exceptions. Imagine! If an exception occurs to an object, The Exception Handling Module has the responsibility to release the object's resources and call the object's destructor to maintain system object data consistency and avoid resource leakage, but now, if there is another exception in the structure analysis process, who will ensure the resource release of this object? Who will handle this new exception? Don't forget that the previous exception has not been processed yet, so it is in conflict or infinite recursive nesting. Therefore, the C ++ standard makes this assumption. Of course, this assumption is completely reasonable. During the object construction process, the resource required by the object may not be satisfied due to limited system resources, leading to exceptions. However, the Destructor can be fully implemented to avoid exceptions, after all, you are releasing resources! For example, if you apply for a salary increase from the company when renewing a contract with the company, the company may not be able to meet your requirements for various other reasons; but if you apply for a salary that is not fully obligated to work, is the company happy to promise you?

What should I do if no exception occurs in the Destructor?

Although the C ++ standard assumes that the Destructor should not, it will not always throw an exception. However, programmers who have had practical software development may realize that the assumption in the C ++ standard is completely standing and talking without feeling back pain, in actual software system development, it is difficult to ensure this. There is no exception in the execution process of all the destructor. This is simply a fantasy, or you may cheat yourself. In addition, do you still have this experience? Sometimes it is more likely that an exception occurs when you analyze an object (release resources) than when constructing an object. For example, a handle indicating a reference count is accidentally incorrect, as a result, resources are released repeatedly and exceptions occur. Of course, most of these errors are caused by small logic problems in the algorithms designed by programmers, but do not forget that the current system is very complicated, it is impossible to ensure that all the programs written by programmers do not have any bugs. Therefore, the guarantee that no exception will occur in the Destructor is indeed a bit idealistic. What should I do if no exception occurs in the Destructor? We can't watch the system crash!

In fact, there is still a good solution. That is, the exception is completely encapsulated inside the destructor, and the exception is never thrown out of the function. This is a very simple and effective method. In this way, make some changes to the above program, then the program will avoid the bad luck of crash. As follows:

[CPP]
View plaincopy

  1. Class mytest_base
  2. {
  3. Public:
  4. Virtual ~ Mytest_base ()
  5. {
  6. Cout <"start preparing to destroy an object of the mytest_base type" <Endl;
  7. // A small change. Completely encapsulate exceptions in the destructor
  8. Try
  9. {
  10. // Note: An exception is thrown in the destructor.
  11. Throw STD: exception ("throwing an exception intentionally in the destructor, test! ");
  12. }
  13. Catch (...) {}
  14. }
  15. Void func () Throw ()
  16. {
  17. Throw STD: exception ("intentionally throw an exception, test! ");
  18. }
  19. Void other (){}
  20. };

The running result is as follows:
Start preparing to destroy an object of the mytest_base type.
Intentionally throw an exception and test it!

How are you doing? Is everything calm now.

Summary of exceptions thrown in destructor

(1) The execution of destructor in C ++ should not throw an exception;
(2) If an exception is thrown in the destructor, your system will become very dangerous. It may not happen for a long time; however, your system may sometimes crash inexplicably and quit without any signs. It's hard to find out where the problem is;
(3) When some (even a little) Exceptions occur in a destructor, then, we must completely encapsulate this possible exception in the destructor, and never let it throw out of the function (this is a perfect trick! Haha !);
(4) The hero, a Yu, vomited blood to remind his friends that the above summary should be noted. The failure of unknown program causes by throwing exceptions in the Destructor is a fatal internal injury of many systems!

At this point, in the C ++ program, how to handle exceptions thrown in various possible places has been basically discussed! Starting from the next article, we will continue to discuss other issues related to c ++ exception handling. Friends, continue!

From: http://blog.csdn.net/qwer_boo/article/details/6455865

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.