Object robbery-constructor and destructor exceptions

Source: Internet
Author: User

Constructor and destructor manage the creation and release of objects respectively, and take charge of the process of object birth and death. When an object is born, the constructor is responsible for creating and initializing the internal environment of the object, including allocating memory, creating internal objects, and opening related external resources. When an object dies, the Destructor is responsible for shutting down resources, releasing internal objects and allocated memory.

IfProgramCodeIf there is a problem, memory leakage often occurs, which may cause the system to be compromised. A large number of facts show that the program with very rigorous business logic code still finds Memory leakage during operation, mostly because of the Code problems in the construction and analysis components.

Many programmers are used to object-oriented programming. They need to create an object and release it when not in use. This habit simplifies our thinking and is the benefit of object-oriented programming. Perhaps because of this habit, many programmers ignore the possibility of exceptions during the moments of object life and death, but this phenomenon deserves our careful reflection.

In fact, the exception between objects is a controversial issue. Even differentProgramming LanguageIn addition, they have different attitudes towards the exceptions between objects.

C ++: if an object encounters an exception during its birth, the object is a non-life freak. Since it is not a complete object, there is no structure or release
Description
Method. Therefore, when an exception occurs during the execution of the constructor, C ++ does not call the object's destructor, instead, just clear and release the C ++-managed variable space before the exception is generated, and then the exception
To the programmer.

Delphi (Object Pascal) considers that although an object has an exception during birth, it already has partial life. Since there is a life thing, there should be the right to die. Therefore, if Delphi generates an exception when executing the constructor, it must first call the destructor of the object and then throw an exception to the programmer for processing.

So who's right? Who's wrong?

I think there may not be any results in the day debate on this issue. Therefore, we do not need to be entangled in the arguments of ideas. As long as we know that different programming languages have different processing methods, we should respect the viewpoint of this language when programming. This is what pragmatic programmers should do!

For the C ++ language, the corresponding destructor is not called because of an exception in the constructor, the rest of the Code created before an exception occurs in the constructor cannot be released by the related release code in the destructor. For example:

Class tmyobject
{
PRIVATE:
Totherobject * otherobject;
Public:
Tmyobject ()
{
Otherobject = new totherobject ();

... // The code after this exception will cause otherobject not to be released!

}
~ Tmyobject ()
{
......

Delete otherobject; // when a constructor exception occurs, The Destructor will not be called and the code will not be executed!
}
}

Check whether similar code exists in your program? If so, you should note that such code is not safe in C ++!

So, how should we write security?

In fact, if you create other things in the C ++ constructor, you must consider exceptions in the constructor. When an exception occurs in the constructor, the created items must be released.
And then throw an exception to the upper-layer call code for processing. This is the correct Exception Handling Method in the C ++ constructor. Therefore, the previous constructor should be rewritten to the following form:

Tmyobject ()
{
Otherobject = new totherobject ();
Try
{
The code here is abnormal.
}
Catch (...)
{
Delete otherobject; // ensure that the created items can be released when an exception occurs.
Throw; // throws an exception and sends it to the upper-layer call code for processing.
};
}

If a constructor needs to create many other things, you should write the appropriate try... Catch catch
Nested code in the catch form (or code with the same logic) to ensure the correctness of the constructor. When you see a C ++ programmer writing a bunch of spectacular try
Try... Catch catch code: He must be a very rigorous C ++ programmer.

However, some smart C ++ programmers also find another method that does not use try... catch to handle constructor exceptions, that is, the famous auto_ptr template in the C ++ standard class library.
Class. Auto_ptr is often called a smart pointer. It uses C ++ to automatically release variables when exiting the scope to clear the objects it maintains. Let's look at the rewritten code:

# Include <memory>
# Include <iostream>

Class tmyobject
{
PRIVATE:
STD: auto_ptr <totherobject> otherobject;
Public:
Tmyobject ()
{
Otherobject = new totherobject ();

The Code following ...... // is abnormal. You can also ensure that the otherobject will be automatically released!

}
~ Tmyobject ()
{
// Once the object is handed over to auto_ptr for maintenance, never release the object by yourself. Therefore, nothing can be written here.
}
}

This code is so concise and effective that it is easy to read and maintain.

Why is this mechanism effective? Because the otherobject is defined as a member variable rather than a pointer. In terms of the mechanism for creating objects in C ++, it is necessary to pair objects first.
Before calling the object constructor, you can enter the constructor scope. I
Once the constructor encounters an exception, it is bound to exit the constructor's scope. c ++ naturally releases Member objects and spaces. When the otherobject member variable is released
Destructor to successfully release the real objects managed by the destructor.

However, atuo_ptr also has some side effects during use. For example, if you assign an auto_ptr value to another auto_ptr, the previous auto_ptr will
It is null, which does not conform to the normal meaning of value assignment. This is because auto_ptr overload the value assignment operator. People who do not understand the implementation principle of auto_ptr often make null pointer errors.
Error. Use auto_ptr.Famous saying: "Don't assign an object to two auo_ptr variables", because this will cause an error of releasing an object twice. In either case
Try... catch is troublesome. It is also a good option to use auto_ptr to prevent memory leakage. It seems you like it or not.

In contrast, the exception of the Delphi language in processing constructor is much simpler. Because delphi ensures that the Destructor will be called after the constructor encounters an exception. However, not all destructor meet this condition. Only destroy can, and it is a virtual function.

Tmyobject = Class
Private
Otherobject: totherobject;
Public
Constructor create;
Destructor destroy; override;
End;

Constructor tmyobject. Create;
Begin
Otherobject: = totherobject. Create;

... // The code after this exception can ensure that the Destructor destroy is called to release the otherobject!

End;

Destructor tmyobject. Destroy;
Begin
......
Otherobject. Free; // here otherobject will be correctly released!

End;

Because delphi's "ensure the Destructor mechanism when constructing exceptions" is a very basic code, it can only design a virtual destructor destroy for the root class tobject to call the destructor. That is to say, if the Destructor you write is not reloaded from destroy, "ensure the structure mechanism is invalid when the constructor is abnormal!

At the same time, Delphi provides the Free Method in the root class tobject to facilitate object release. This free method ensures that even if the object is created (the object pointer is nil ),
No error occurs when you call this method. In this way, the statements created in the constructor can correspond to the release statement of the destructor in a concise manner, so that we can look at the code easily. It seems that the free method is well designed.
Bitter!

So what about exceptions in destructor?

An exception occurs in the process of object death, which leads to an interesting problem: "You cannot die" or "You cannot die when you are half dead "! So, is this object dead or alive? This dead and living object is just as interesting as the "schödnex cat" in quantum theory. It does exist, but it's hard to figure it out!

C ++ handles exceptions of destructor, which is similar to General exceptions. It submits exceptions to the upper-layer calling program for processing. If this exception is not handled anywhere, it will cause the current execution thread to terminate unexpectedly! If an destructor exception occurs in the main thread, the program exits immediately!

Because, in the case of an exception in the destructor, if there is code to release the memory after the exception point, the code will not be executed, which will certainly lead to memory leakage. Therefore, "Never throw an exception in the destructor" becomes an iron for compiling C ++ code!

In Delphi, exceptions in destructor are no different from those in other code, and the code will not be executed after an exception occurs (except for the finally part ), the exception will be handled by the upper-layer exception handling code that can be found! If the exception is not processed, the current thread is terminated.

It seems that this destructor exception is not a problem that can be figured out at half past one, and the Delphi method is no better than C ++. Therefore, "Never throw an exception in the Destructor" can still be used as a simple law!

Sometimes, in the face of complicated and confused confusions, you can simply keep in mind the simple principles.

There are too many disappointments in this world, but you still need to continue your life. The sun will still rise every day, hoping to grow in your heart forever...

Leadzen. Shenzhen

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.