C + + Exception security

Source: Internet
Author: User
Tags mutex try catch

Exception-safe code means that two conditions are met

1 Exception Neutrality:

This exception is passed to the outer calling code when your code (including the code you call) throws an exception. (Abnormal neutrality means that any underlying exception is thrown to the upper layer, which is equivalent to being unusually transparent.) )

2. Exception Security:

    • After throwing an exception, the resource does not leak,
    • when an exception is thrown, it does not worsen the original data (for example, normal pointer-to-wild pointers)
    • Try catch less because a large number of Try catch can affect the code logic. Cause the code ugly confusion not elegant

A piece of code to have exception security, must have both exception neutrality and a certain level of exception security assurance

The level of exception safety is generally:

1, the function provides a basic guarantee (the basic guarantee) (no memory leaks and every object within the program is in a legitimate state, there is no flow dislocation, no wild pointers, but is not the exact state of each object can be expected, if an exception occurs, the pointer is in a null pointer state, Or a default state, but the customer cannot predict exactly which one), you can use smart pointers to manage resources for achieving basic assurance

2, the function provides a strong guarantee (the strong guarantee), the strong guarantee means that the success or rollback guarantee, the function of the exception is not changed to the program, provides the rollback mechanism when the exception occurs.

After invoking a function that provides a strong guarantee, there are only two possible program states: The function was executed successfully as expected, or the function rollback continues to hold the state when the function is called. In contrast, if an exception is thrown by a function that only provides a basic guarantee, the program may exist in any legitimate state.

The effective solution for a function to provide a strong guarantee is

Copy-and-swap:

Make a copy of the object you want to change, and then make all the necessary changes on this copy. If some action in the change process throws an exception, the original object remains unchanged. After all the changes have been completely successful, the changed object and the original object are swap in an operation that does not throw an exception.

3. The function has a non-throwing guarantee (the Nothrow guarantee), and the operation for all built-in types (for example, ints, pointers, and so on) is not thrown (nothrow) (that is, provides no-throw guarantees). This is an essential component of the exception-safe code.

Precautions:

Exception security The most critical is: Swap ctor Dctor does not occur exception guarantee, only the success or termination of the program two states

The exception security level of a function is a function that depends on the lowest exception security level in the function it calls.

c++11 new noexcept keyword, in void func () noexcept{}noexcept guarantees that this function does not throw an exception, only terminates the program and executes both states successfully.

Noexcept can accept a constant expression, noexcept (constexpr ... When the constant expression is converted to true, the function guarantees that the exception is not thrown.

From an exception-safe point of view, a non-throwing function (Nothrow functions) is excellent, but it is impossible to call a function that throws an exception outside C of C + +. Use anything that dynamically allocates memory (for example, all STL containers) If you cannot find enough memory to satisfy a request, in a typical case it throws a Bad_alloc exception . As long as you can do it, you provide a non-throwing guarantee, but for most functions, the choice is between the basic guarantee and the strong guarantee.

However, not all functions can guarantee the exception, consider such a function, the function inside the function is a database operation, once an exception occurs, it is difficult to undo the changes to the database. If you want to do an abnormal strong guarantee guarantee, it is very difficult to do things.

Therefore, it is relatively easy to guarantee the abnormal safety of functions that only change the local variables. It becomes much more difficult to get involved in global variables and so on in the operation of a function.

A good way to solve abnormal security:

1, use RAII, use smart pointers to manage memory. Due to the guarantee of the unwind mechanism, when an exception occurs, the destructor of the constructed local object in the function stack is called by one by one, releasing the resource within the destructor and eliminating the problem of memory leak.

2, do the programming. In particular, the correct use of the rollback mechanism in the event of an exception, Copy-and-swap is an effective method.

3, notice the calling function inside the function that needs the exception guarantee, and the exception security level is determined by the function with the lowest level exception guarantee.

A system is not exceptionally secure as a whole, even if only one function is not exceptionally secure, since calling that function can leak resources and worsen data structures.

4, for some programs that need to ensure performance, in providing basic exception security, note that the stack fallback mechanism simply calls the destructor, for the built-in type of operation will not be rolled back, so. As with some built-in type variables of the accumulator, it is important to note that the function is successfully executed and then accumulated. Avoid data structure deterioration. To reassign a resource to a variable that already has a resource, you should first empty the resource that freed the variable, and then set the pointer to nullptr to prevent an exception from being thrown during resource reallocation, causing the pointer to become a wild pointer.

5, Stream object, resource object, new object, should not be directly as a parameter, once thrown an exception, it may cause serious problems, the function may be wrong execution, the resource may leak. For function arguments and global variables used within functions, it should be ensured that the inside of the function is a normal state.

6. Reducing the use of global variables, it is difficult to make the function of the global variable to be abnormal, and the stack retreat is only effective for local variables.

7, if you do not know how to handle the exception, do not catch the exception, the direct termination than the swallowing exception is not handled better

8. Ensure that the structure of the destruction swap will not fail

Here are a few things to note:

In a constructor, if an exception is thrown, the destructor of the class currently being constructed is not called, because the class currently being constructed is not constructed, only the destructor has been constructed to complete the member and the parent class, so, very prone to memory leaks, here to be handled with care, using RAII, smart pointers, Noexcept guarantees that no exception and worsening data will be thrown.

Reference article:

1: Object Life and death-constructors and destructor exceptions

http://blog.csdn.net/leadzen/article/details/1783116

2:c++ Maxim: Code to fight for exception security

Http://dev.yesky.com/490/2087990.shtml

Abnormal security (Exception safety) is a bit like pregnancy (pregnancy) ... However, please take this idea for a moment first. We can't really talk about fertility (reproduction) until we get through the courtship period (courtship). (This paragraph of the 3 words used by the author has a pun meaning, pregnancy can also be understood as meaningful, reproduction can also be understood as reproduction, regeneration, courtship can also be understood as a fight, seeking. In order to correspond with the subsequent translation, the present translation is followed. --the translator's note)

Suppose we have a class that represents a GUI menu with a background image. This class is designed to be used in a multithreaded environment, so it has a mutex (mutex) for parallel control (concurrency):

Class Prettymenu {
Public
...
void Changebackground (std::istream& imgsrc); Change background
...//image

Private

Mutex mutex; Mutex for this object

Image *bgimage; Current background image
int imagechanges; # of times image has been changed
};


Consider the possible implementation of this prettymenu Changebackground function:

void Prettymenu::changebackground (std::istream& imgsrc)
{
Lock (&mutex); Acquire mutex (as in Item 14)

Delete Bgimage; Get rid of old background
++imagechanges; Update image Change Count
Bgimage = new Image (IMGSRC); Install new background

Unlock (&mutex); Release Mutex
}


From the point of view of abnormal security, this function is rotten to the extreme. There are two requirements for exception safety, and none of this is satisfied.

When an exception is thrown, the exception-safe function should:

· no resource leaks. The above code does not pass this test because if the "new Image" expression produces an exception, the call to unlock will never be executed, and the mutex is imgsrc forever.

· data structure deterioration is not allowed . If "New Image (IMGSRC)" Throws an exception, Bgimage is left pointing to a deleted object. In addition, although a new image has not been set in place, the imagechanges has been added. (On the other hand, the old image was explicitly deleted, so I suppose you would argue that the image has been "changed".) )

It's easier to circumvent resource leaks, and we've explained how to use Object management resources, and also discuss the introduction of Lock classes as a stylish way to ensure that mutexes are freed:

void Prettymenu::changebackground (std::istream& imgsrc)
{
Lock ml (&mutex); From Item 14:acquire Mutex and
Ensure its later release
Delete Bgimage;
++imagechanges;
Bgimage = new Image (IMGSRC);
}


One of the best things about resource management classes like Lock is that they usually make the function shorter. Do you see that the call to unlock is no longer needed? As a general rule, less code is better code. Because this can be less misguided and less misleading in times of change.

As the resource leaks are behind us, we can focus our attention on the deterioration of the data structure. Here we have a choice, but before we can choose, we have to face the terminology that defines our choices. The exception security function provides one of the following three guarantees:

• The function provides a basic guarantee (the basic guarantee), promising that if an exception is thrown, everything left in the program is in a valid state. No objects or data structures are destroyed, and all objects are internally reconciled (all class invariants are satisfied). However, the precise state of the program may not be predictable. For example, we can rewrite changebackground so that if an exception is thrown, the Prettymenu object can continue to retain the original background image, or it can hold some default background image, but the customer cannot predict exactly which. (To find out, they probably have to call a member function that tells them what the current background image is.)

• The function provides a strong guarantee (the strong guarantee), promising that if an exception is thrown, the state of the program will not change. Calling such functions is extremely faint in the sense that if they succeed, they are completely successful, and if they fail, the state of the program is as if they had never been called.

• It is easier to work with a function that provides a strong guarantee than to work with a function that provides only basic guarantees, because after calling a function that provides a strong guarantee, there are only two possible program states: The function was executed successfully as expected, or the state when the function was invoked. In contrast, if an exception is thrown by a function that only provides a basic guarantee, the program may exist in any legitimate state. The

function provides a non-throwing guarantee (the Nothrow guarantee), which promises never to throw exceptions because they only do what they promise to do. All operations on built-in types (for example, ints, pointers, and so on) are non-throwing (nothrow) (that is, offering no-throw guarantees). This is an essential component of the exception-safe code.

It seems reasonable to assume that a function with an empty exception specification (Exception specification) is not thrown, but this is not necessarily true. For example, consider this function:

int dosomething () throw (); Note Empty exception spec.


This is not to say that dosomething never throws an exception, but that if DoSomething throws an exception, it is a serious error and should call the unexpected function [1]. In fact, dosomething may not provide any exception guarantees at all. The declaration of a function, if any, including its exception specification (Exception specification), does not tell you whether a function is correct, portable, or efficient, and, even if it does, it does not tell you which exception security guarantee it provides. All of these attributes are determined by the implementation of the function, not by its declaration.

[1] Information about the unexpected function can be turned to your favorite search engine or a comprehensive C + + textbook. (You may be fortunate enough to search for set_unexpected, which is used to specify the unexpected function.) )

The exception security function must provide one of the three guarantees mentioned above. If it is not provided, it is not exceptionally secure. The choice, then, is to decide what kind of assurance you are going to provide for each function you write. Unless you're dealing with a legacy of non-exception-safe code (which we'll discuss later), not providing exception security guarantees can be an option only if your most sophisticated requirements Analysis team identifies a requirement for your application that leaks resources and runs on corrupted data structures.

As a general rule, you should provide the most powerful guarantee that is actually achievable. From an exception-safe point of view, a non-throwing function (Nothrow functions) is excellent, but it is impossible to call a function that throws an exception outside C of C + +. Use anything that dynamically allocates memory (for example, all STL containers) If you cannot find enough memory to satisfy a request, in a typical case it throws a Bad_alloc exception. As long as you can do it, you provide a non-throwing guarantee, but for most functions, the choice is between the basic guarantee and the strong guarantee.

In the case of Changebackground, it is not difficult to provide a similar strength guarantee. First, we change the type of the Prettymenu bgimage data member from a built-in image* pointer to one of the smart resource management pointers described in Item 13. Frankly speaking, this is a very good idea in the basic principles of preventing resource leaks. The fact that it helps us to provide strong exception security guarantees further reinforces the view that managing resources using objects (such as smart pointers) is the foundation of good design. In the following code, I show the use of tr1::shared_ptr because it's more intuitive behavior when making a regular copy makes it preferable to auto_ptr.

Second, we rearrange the statements in the Changebackground so that the imagechanges is incremented until the image changes. This is a good strategy--until something really happens, and then change the state of an object to indicate that something has happened.

This is the code after the change:

class Prettymenu {
... br> std::tr1::shared_ptr<image> Bgimage;
...
};

void Prettymenu::changebackground (std::istream& imgsrc)
{
Lock ml (&mutex);

Bgimage.reset (New Image (IMGSRC));//replace bgimage ' s internal
//pointer with the result of the
//"New Ima GE "expression
++imagechanges;
}


Note that it is no longer necessary to manually delete the old image because it has already been processed inside the smart pointer. Additionally, the deletion behavior occurs only if the new image is successfully created. More precisely, this function is called only if the parameter of the Tr1::shared_ptr::reset function (the result of "new Image (IMGSRC)") is successfully created. Delete is only used inside the call to reset, so if the function is never entered, the delete is never used. Also note that the use of an object that manages resources (dynamically assigned Image) (TR1::SHARED_PTR) shortens the length of the Changebackground again.

As I said, these two changes are almost capable of providing Changebackground with strong exception security assurances. What's in the ointment? Parameter imgsrc. If an Image's constructor throws an exception, the read marker of the input stream may have been moved, and such a move becomes a change in the state that is visible to the rest of the program. Until Changebackground begins to solve the problem, it can only provide basic exception security assurances.

Anyway, let's put it aside and still pretend that changebackground can provide a strong guarantee. (I believe you can do this in at least one way, perhaps by changing its parameters from one IStream to the file name of the file that contains the image data.) There is a common design strategy that can typically produce a strong guarantee, and familiarity with it is essential. This strategy is called "Copy and Swap". It's a simple principle. Make a copy of the object you want to change, and make all the necessary changes on the copy. If some action in the change process throws an exception, the original object remains unchanged. After all the changes have been completely successful, the changed object and the original object are exchanged in an operation that does not throw an exception. This is usually done by putting all the data in each object from a "real" object into a separate implementation object, and then handing a pointer to the implementation object to the real object. This is often referred to as "Pimpl idiom", and Item 31 describes some of its details. For Prettymenu, it is generally like this:  

struct Pmimpl {//Pmimpl = "Prettymenu
std::tr1::shared_ptr<image> bgimage; Impl. "; See below for
int imagechanges,//Why it's a struct
};

class Prettymenu {
...

Private:
Mutex mutex;
std::tr1::shared_ptr<pmimpl> pimpl;
}; 

void Prettymenu::changebackground (std::istream& imgsrc)
{
using Std::swap;//See Item

Lock ml (&mutex); Acquire the mutex

std::tr1::shared_ptr<pmimpl>//copy obj. Data
Pnew (new Pmimpl (*pimpl));

Pnew->bgimage.reset (New Image (IMGSRC));//Modify the copy
++pnew->imagechanges;

Swap (Pimpl, pnew);//Swap the new
//data into place

}//Release the mutex


In this example, I chose to make Pmimpl a struct rather than a class, because by letting Pimpl be private, you can ensure that the Prettymenu data is encapsulated. It is not so convenient to make Pmimpl into a class, but it does not add any benefit. (This will also make the object-oriented neat people desperate.) If you want, Pmimpl can be nested inside prettymenu, and packing problems like this have nothing to do with the problem of writing unusually secure code that we care about here.

The COPY-AND-SWAP strategy is an excellent way to completely change or not change the state of an object at all, but, in general, it does not guarantee that all functions are strong and exceptionally secure . To clarify the reason, consider a changebackground abstract avatar--somefunc, which uses copy-and-swap, but it contains calls to the other two functions (F1 and F2):

void SomeFunc ()
{
...//Make copy of the local state
F1 ();
F2 ();
...//Swap modified state to place
}


Obviously, if F1 or F2 are less powerful than strong, somefunc can be very hard to be exceptionally secure. For example, suppose F1 provides only basic guarantees. In order for SomeFunc to provide a strong guarantee, it must write code to determine the state of the entire program before calling F1, and to capture all exceptions from F1 and revert to its original state.

Thatso that F1 and F2 are strong and exceptionally safe, things are not better. If the F1 run is complete, the state of the program has changed without a doubt, so if the subsequent F2 throws an exception, even if F2 does not change anything, the state of the program has been different from calling SomeFunc.

The problem is side effects. As long as the function only works on the local state (for example, SomeFunc only affects the state of the object that called it), it is relatively easy to provide a strong guarantee. When the side effects of a function affect non-local data, it is much more difficult. For example, if the side effect of calling F1 is to change the database, it is very difficult to make SomeFunc a brute force exception security. In general, there is no way to undo a database change that has been committed, and other database customers may have seen the new state of the database.

A problem like this will prevent you from providing a powerful guarantee for a function, even if you want to do it. Another problem is efficiency. The point of Copy-and-swap is the idea of changing the copy of an object's data and exchanging the changed data with the original data in an operation that does not throw an exception. This requires making a copy of every object to be changed, which may use time and space that you cannot or will not willingly spend. A strong guarantee is well worth it, and when it is available you should provide it unless it is 100% available.

When it is not available, you must provide basic assurance. In practice, you may find that you can provide a strong guarantee for some functions, but the cost of efficiency and complexity makes it difficult to support a large number of other functions. Whenever you make a reasonable effort to provide a strong guarantee, no one will stand in your position to criticize you simply by providing a basic guarantee. For many functions, the basic guarantee is a perfectly reasonable choice.

If you write a function that does not provide an exception security guarantee at all, things will be different, because at this point the presumption of guilt is justified until you prove that you are innocent. You should write code that is unusually secure. Unless you can make a convincing plea. Consider the implementation of SomeFunc again, which calls the functions F1 and F2. Suppose F2 does not provide exceptional security guarantees at all, or even basic guarantees. This means that if an exception occurs in the F2, the program may leak resources inside the F2. This also means that F2 may deteriorate the data structure, for example, the sorted array may no longer be sorted, an object that is being transferred from one data structure to another may be lost, and so on. There is no way that somefunc can make up for these problems. If the function called by SomeFunc does not provide an exception security guarantee, SOMEFUNC itself cannot provide any guarantees.

Please allow me to return to the topic of pregnancy. A woman is either pregnant or not. Local pregnancies are never possible. Similar to this, a software is either unusually secure or not. There is no such thing as a local exception-safe system. A system is not exceptionally secure as a whole, even if only one function is not exceptionally secure, since calling that function can leak resources and worsen data structures. Unfortunately, many of C + + 's legacy code is not unusually secure when it is written, so many systems today are not exceptionally secure. They are mixed with code written in a non-exception-safe (exception-unsafe) manner.

There is no reason for this state of affairs to continue forever. When writing new code or changing existing code, carefully consider how to make it exceptionally secure. Start by using object management resources. This can prevent resource leaks. Next, decide which of the three types of exception security assurances you can actually provide the strongest guarantee for each function you write, and only when you don't have the option of calling legacy code can you be satisfied with no guarantees. Both the client for your function and the future maintenance staff will document your decision. The exception security guarantee of a function is the visible part of its interface, so you should deliberately choose it, just as you deliberately choose other aspects of a function interface.

40 years ago, the code that was everywhere Goto was revered as best practice. Now we struggle to write structured control processes. 20 years ago, globally accessible data was respected as a best practice. Now we're struggling to encapsulate the data, and 10 years ago, writing a function without having to consider the impact of the exception was a best practice. Now we struggle to write code that is unusually secure.

time is passing. We live. We learn.

Things to Remember

• Even when an exception is thrown, the exception-safe function does not reveal the resource or allow the data structure to deteriorate. Such functions provide basic, strong, or non-throwing guarantees.

• Strong guarantees can often be achieved through copy-and-swap, but strong guarantees are not available for all functions.

• A function can usually provide a guarantee that is not stronger than the weakest guarantee in the function he invokes.

# # #adv # #

3: How to Write code with exception security

http://blog.csdn.net/wingfiring/article/details/660900

C + + Exception security

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.