Cannot throw an exception inside a destructor

Source: Internet
Author: User
Tags exception handling

From the syntax above, it is possible for destructors to throw exceptions, and C + + does not prevent destructors from throwing exceptions, but C + + does not recommend this practice, and it is dangerous to throw exceptions from destructors.

Destructors may be invoked when an object ends in its normal life cycle, or when an exception occurs when it is scavenged from the function stack. The first case throws an exception without unpredictable results, can be captured normally, but in the latter case, because of an exception to the function, the destructor of the function's local variable is invoked, and the destructor throws an exception, and the exception that is thrown by the local object should be captured by the function in which it resides. Now that the function has already had an exception, it must not be caught, so the exception handling mechanism can only invoke terminate (). If you really have to throw an exception from a destructor, you should first check whether there are any exceptions that are still unhandled, and if not, you can throw them normally.


When the destructor is invoked to execute.

For C + + programmers, this problem is relatively simple, but the more nagging Ahan or suggestions should be mentioned here, but also to review the knowledge of C + +, and this will be the next discussion and understanding by some help. Let's look at a simple example. As follows:

Class Mytest_base
{
Public
Virtual ~ mytest_base ()
{
cout << "destroy a Mytest_base type of object" << Endl;
}
};


void Main ()
{
Try
{
Constructs an object, and the destructor is executed when the Obj object leaves the scope
Mytest_base obj;

}
catch (...)
{
cout << "Unknow exception" << Endl;
}
}

Compiled to run the above program, the results from the program will indicate that the object's destructor was executed, but when it was executed. As stipulated in the C + + standard, an object should be invoked to run when it leaves its scope. Actually each manufacturer's C + + compiler also satisfies this request, takes the VC to do a test verification. , the following is a list of related program fragments that were copied by the small example program just above when it was debugged. Note that the Obj object will be inserted into a piece of code by the compiler when leaving the try block, implicitly invoking the object's destructor. As follows:


325:try
326: {
00401311 mov dword ptr [ebp-4],0
327://Construct an object, the destructor will be executed when the Obj object leaves the scope
328:mytest_base obj;
00401318 Lea Ecx,[obj]
0040131B call @ILT +40 (mytest_base::mytest_base) (0040102d)
329:
330:}//See below, the compiler inserts a section of code that implicitly invokes the object's destructor
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@@3v $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@@ zzfcthotfixz @ @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 a destructor
1, still is the first look at the example, as follows:

Class Mytest_base
{
Public
Virtual ~ mytest_base ()
{
cout << "Start preparing to destroy a mytest_base type of object" << Endl;

Note: An exception was thrown in the destructor
Throw std::exception ("intentionally throwing an exception in a destructor, testing.") ");
}

void Func () throw ()
{
Throw Std::exception ("intentionally throws an exception, tests.") ");
}

void Other () {}

};


void Main ()
{
Try
{
Constructs an object, and the destructor is executed when the Obj object leaves the scope
Mytest_base obj;


Obj. Other ();
}
catch (Std::exception e)
{
cout << e.what () << Endl;
}
catch (...)
{
cout << "Unknow exception" << Endl;
}
}

The results of the program running are:
Start preparing to destroy an object of mytest_base type
Intentionally throwing an exception in the destructor, testing.

From the above program to run the results, there is nothing special in the program is the first to construct an object, when the object is left its scope, the destructor is called, when the destructor throws a std::exception type of exception, so the following catch (std:: Exception e) block captures this exception and prints out the exception error message. This process seems to show that the exception that occurred in the destructor is not much different from the exception that occurred elsewhere (such as in the object's member function), except that the destructor is implicitly invoked, but this does not affect the mechanism of exception handling at all. What is the difference? What is the mystery. Go ahead and look down.

2, on the basis of the above program to do a little change, the program code is as follows:

void Main ()
{
Try
{
Constructs an object, and the destructor is executed when the Obj object leaves the scope
Mytest_base obj;


The following statement is a newly added
Calling this member function throws an exception
Obj. Func ();

Obj. Other ();
}
catch (Std::exception e)
{
cout << e.what () << Endl;
}
catch (...)
{
cout << "Unknow exception" << Endl;
}
}

Note that the modified program now runs the results: Unfortunately, the program crashes after printing a statement on the console (if the program is a debug version, it displays an assertion that the program will be terminated; If the release version, the program is executed after the Terminate () function exits). The debug version of the program that runs on the hero Ahan's machine results in the following:

Many friends may feel silly to this result, this is simply inexplicable wonderful. It's whose fault it is. Is it a problem with the newly added code, but that's not going to happen at all. (In fact, many programmers friends have been too much of such a similar injustice, such as a program originally run very well, after the expansion of functions, the program is often a crash phenomenon.) In fact, sometimes the program expansion also did not add how much code, and the relevant programmers are very careful to carefully check their added code, confirm that the code added later is really no problem ah. may be related to the person in charge may not think so, feel that the program has been running pretty good, after you have this modification after the error, can not you add the code caused by the problem. is really the field of program development Dou injustice. In fact, this kind of reasoning is completely unfounded and justified, objectively and fairly, said that the collapse of the program and the subsequent addition of the module code will certainly have some relevance. But the real bug may have existed in the original system, but it has not been induced to show it before. Look at that. The protagonist Ahan again bifurcation problem, feeling and hair. Let's get back to the point. )

What the hell is the problem here? This is actually caused by the exception thrown in the destructor, but it's even more surprising that the exception thrown in the destructor is no problem. Just one of the examples has not been tested already. Yes, but that's just an illusion. If you want to make your system reliable, secure, and run for a long time without trouble, you are in the process of exception handling design and coding procedures, at least to ensure that the destructor is not allowed to throw exceptions, but also in the C + + standard specifically stated this point, but it does not explain the real reason. So what exactly is it? Why does the C + + standard stipulate that an exception cannot be thrown in a destructor. This is indeed a very difficult issue and it is difficult to articulate it very clearly. But the protagonist Ahan is still willing to discuss its own understanding of the problem and ideas, hope to be able to reach some understanding with the programmer friends consensus.

  C + + exception handling model is designed for the C + + language, further said, it is actually for the C + + language object-oriented and services, we in the previous article many times the trouble to declare, C + + exception handling model the biggest feature and advantage is to C + + Provides the most powerful and seamless support for object-oriented objects. Okay, that's it. So if an object has an exception during run time, the C + + exception handling model has the responsibility to clear those objects that have been invalidated due to an exception (that is, the object is beyond its original scope) and to release the resources that the object originally allocated, which is the task of invoking the destructor of these objects to complete the release of the resource. So in this sense, destructors have become part of exception handling. I do not know whether you understand this passage contains the true intrinsic meaning does not, that is the above discussion of C + + exception handling model It actually has a prerequisite assumption--destructors should not be thrown again. Imagine. If the object is out of an exception, now exception processing module in order to maintain the consistency of the system object data, to avoid resource leakage, has the responsibility to release the object's resources, call the object's destructor, but now if the process again abnormal, then ask who will ensure that the object of the release of resources? And who will deal with this new anomaly? Don't forget that one of the previous exceptions is not finished yet, so it's stuck in a contradiction, or infinite recursive nesting. So the C + + standard makes this assumption, of course, this assumption is entirely reasonable, in the construction of objects, perhaps due to limited resources and the resources of the object can not be met, resulting in abnormal appearance, but the destructor is completely can do to avoid abnormal occurrence, after all, you are releasing resources ah. If you apply to the company for a raise when you renew your contract with the company, you may not be able to meet your requirements for a variety of other reasons, but if you are willing to apply for a full and compulsory salary, will the company be willing to promise you?

What to do if there is no guarantee that no exception will occur in the destructor.

Although the C + + standard assumes that destructors should not be in the destructor, they are not allowed to throw exceptions. But there are real software developers in the development of friends may realize that the C + + standard in the assumption is completely standing in the speech do not feel lumbago, the actual software system development is difficult to ensure that. The execution of all destructors does not occur at all without a single exception, which is impossible, or deceiving yourself. And if you've ever had this experience, sometimes it's easier to find that an object (releasing a resource) is more prone to an exception than constructing an object, such as an error in a handle that represents a reference count, which results in an exception when a resource is repeatedly released, Of course, most of these errors are due to the logic of the programmer's algorithm, but do not forget that the current system is very complex, it is impossible to ensure that all programmers write the program completely without bugs. So it is a little idealistic to put an end to the assurance that no exception will occur in the destructor. Then what to do when there is no guarantee that an exception does not occur in the destructor. We can't watch the system crash.

In fact, there is a very good way to solve. That is, to completely encapsulate the exception inside the destructor, and never let the exception throw out the function. This is a very simple and very effective method. In this way the above procedure is changed a little, then the program will avoid the collapse of doom. As follows:

Class Mytest_base
{
Public
Virtual ~ mytest_base ()
{
cout << "Start preparing to destroy a mytest_base type of object" << Endl;

A little bit of change. Completely encapsulate the exception inside the destructor
Try
{
Note: An exception was thrown in the destructor
Throw std::exception ("intentionally throwing an exception in a destructor, testing.") ");
}
catch (...) {}

}

void Func () throw ()
{
Throw Std::exception ("intentionally throws an exception, tests.") ");
}

void Other () {}

};

The results of the program running are as follows:
Start preparing to destroy an object of mytest_base type
Deliberately throw an exception to the test.

Well, now that everything is calm.

Summary of exceptions thrown in destructors

(1) The execution of destructors in C + + should not throw exceptions;
(2) If an exception is thrown in the destructor, then your system will become very dangerous, perhaps for a long time nothing will happen, but perhaps your system will sometimes inexplicably collapse and quit, and there is no sign, and the collapse of your teeth will find it difficult to see where the problem appears;
(3) When there is some possibility (even a little possible) of an exception in a destructor, it is necessary to encapsulate the possible exception completely inside the destructor and never let it throw out the function. Oh. );
(4) The protagonist Ahan vomiting blood to remind friends, be sure to remember these several summaries, the destructor throws an exception causes the program unexplained collapse is the fatal internal injury of many systems.

This topic has been basically discussed in the C + + program as to how the exceptions thrown by the various possible places will be handled. Continue with the next article to discuss some of the other aspects of C + + exception handling. Friends, CONTINUE.

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.