Explore C + + memory Recycling

Source: Internet
Author: User
Tags function definition rollback

Turn from: http://club.topsage.com/thread-541343-1-1.html

3.1 C + + Memory object Big battle
If a person calls himself a program master and knows nothing about memory, then I can tell you that he must be bragging. Writing programs in C or C + + requires more attention to memory, this is not just because the allocation of memory directly affects the efficiency and performance of the program, but more important, when we operate the memory inadvertently will have problems, and many times, these problems are not easy to detect, such as memory leaks, such as hanging pointers. I'm not here today to discuss how to avoid these problems, but rather to understand the C + + memory object from another perspective.

As we know, C + + divides memory into three logical areas: heaps, stacks, and static storage. That being the case, I call the objects located in them as heap objects, stack objects, and static objects, respectively. So what's the difference between these different memory objects? Heap objects and stack objects have their pros and cons. How to prevent the creation of heap objects or stack objects. These are the themes of today.

3.1.1 Basic Concepts

Take a look at the stack first. Stacks, typically used to hold local variables or objects, such as the objects we declare in the function definition like the following statement: Type Stack_object; Copy Code Stack_object is a stack object whose lifetime begins at the definition point and ends when the function returns.

In addition, almost all temporary objects are stack objects. For example, the following function definition: type fun (type Object); Copy code This function generates at least two temporary objects, first of all, the parameters are passed by value, so the copy constructor is invoked to generate a temporary object object_copy1, which is used inside the function not using object, but object_copy1, nature, object_ Copy1 is a stack object, it is released when the function returns, and this function is returned by the value, and when the function returns, if we do not consider the return value optimization (NRV), a temporary object object_copy2 will be generated, which will be released within a period of time after the function returns. For example, a function has the following code: Type TT, result; Generate two Stack objects
tt = Fun (TT); When the function returns, it generates a temporary object object_copy2 the execution of the second statement above the copy code is the first time the function fun returns with a temporary object object_copy2, and then the assignment operator is invoked to perform the TT = OBJECT_COPY2 ; Call the assignment operator to copy the code see. The compiler, in our unconscious circumstances, so many temporary objects are generated for us, and the time and space overhead of generating these temporary objects can be very large, so you may understand why it is best to pass a const reference pass instead of a function argument by value for a "big" object.

Next, look at the heap. The heap, also called the free storage area, is dynamically allocated during the execution of the program, so its most characteristic is dynamic. In C + +, the programmer is responsible for the creation and destruction of all heap objects, so if it is not handled properly, memory problems can occur. If a heap object is assigned, when you forget to release, you create a memory leak, and if you have disposed of the object without leaving the corresponding pointer null, the pointer is the so-called "hanging pointer", and when you use this pointer again, illegal access occurs, causing the program to crash.

So, how do you allocate the heap objects in C + +? The only way to do that is to use new (of course, the class malloc instruction also gets the C-heap memory), and as soon as new is used, a chunk of memory is allocated in the heap and a pointer to the heap object is returned.

Let's look at the static storage area again. All static objects, global objects are allocated in the static store. About global objects, which are allocated before the main () function is executed. In fact, before the display code in the main () function executes, a compiler-generated _main () function is invoked, and the _main () function performs the construction and initialization of all global objects. At the end of the main () function, the Exit function generated by the compiler is invoked to free all global objects. For example, the following code: void Main (void)
{
.//Explicit code
The copy code is actually transformed into this: void Main (void)
{
_main (); Implicit code, generated by the compiler to construct all global objects
...//Explicit code
Exit (); Implicit code, generated by the compiler to release all global objects
Copy code So, after you know this, this can lead to some tricks, such as assuming that we're going to do some preparation before the main () function executes, then we can write these preparations into a custom global object constructor, so that before the explicit code of the main () function executes, The constructor for this global object is invoked to perform the expected action, which is what we are doing. Just speaking of the global object in the static store, then, the local static object. A local static object is often defined in a function, just like a stack object, except that it has a static keyword in front of it. The lifetime of a local static object is invoked for the first time from its function, or rather, when it is first executed to the declaration code of the static object, and the static local object is generated until the end of the entire program.

There is also a static object, which is the static member of class. In considering this situation, there are some more complex issues involved.

The first problem is the lifetime of the static member object of class, where the static member object of class is generated with the first class object, and dies at the end of the program. That is, there is a case where we define a class in the program that has a static object as a member, but in the course of execution, if we don't create any of the class object, then it doesn't produce that static object that class contains. Also, if you create more than one class object, all of these objects share that static object member.

The second problem is when the following conditions occur: class Base
{
Public
Static Type S_object;
}

Class Derived1:public Base//Public inheritance
{
...//Other data
}

Class Derived2:public Base//Public inheritance
{
...//Other data
}

Base example;
Derivde1 example1;
Derivde2 example2;
Example.s_object = ...;
Example1.s_object = ...;
Example2.s_object = ...; Copy code note the three statements marked bold above, and the s_object they are accessing are the same objects. The answer is yes, they do point to the same object, which does not sound like real, does it? But it's true, you can write a simple code to verify it. What I'm going to do is explain why. We know that when a class, such as Derived1, inherits from another class such as base, it can be thought of as a Derived1 object containing a base type object, which is a subobject. The approximate memory layout for a Derived1 object is as follows:
  
Let's think about that when we pass a Derived1 object to a function that accepts unreferenced base-type parameters, the cut occurs. As you know now, it's just taking out the subobject in the Derived1 object, ignoring all the other Derived1 custom data members, and then passing the subobject to the function (actually, A copy of this subobject is used in the function.

All objects that inherit from a derived class of the base class all contain a base-type subobject (this is the key to using the base pointer to point to a Derived1 object, and nature is also the key to polymorphism), All subobject and all base-type objects share the same S_object object, and naturally, instances of classes in the entire inheritance system derived from the base class share the same S_object object. The example, example1, example2 object layouts mentioned above are shown in the following illustration:

3.1. Comparison of 23 kinds of memory objects

Stack object's advantage is automatically generated at the appropriate time, and automatically destroyed at the appropriate time, do not need the programmer to worry; and stack objects are generally faster to create than heap objects, because when allocating heap objects, the operator new operation is invoked, and operator new uses some kind of memory space search algorithm. The search process may be time-consuming, the generation of stack objects is not so cumbersome, it just needs to move the top of the stack pointer on it. But note that, usually the stack space capacity is small, is generally 1mb~2mb, so the larger size of the object is not suitable for distribution in the stack. In particular, it is best to note that recursive functions do not use stack objects, because as the depth of the recursive call increases, the required stack space will increase linearly, when the required stack space is not enough, it will cause a stack overflow, which will result in run-time errors.

Heap objects, their time of creation and the time of destruction are precisely defined by the programmer, that is, the programmer has complete control over the life of the heap object. We often need this kind of object, for example, if we need to create an object that can be accessed by multiple functions, but do not want to make it global, then creating a heap object at this time is certainly a good choice, and then passing a pointer to the heap object between the functions enables the sharing of that object. In addition, the heap capacity is much larger than the stack space. In fact, when there is not enough physical memory, if you need to generate a new heap object at this point, there is usually no run-time error, but the system uses virtual memory to extend the actual physical memory.

Next look at the static object.

The first is the global object. Global objects provide one of the simplest ways to communicate between classes and functions, although this approach is not elegant. In general, in a fully object-oriented language, there is no global object, such as C #, because global objects imply insecurity and high coupling, the excessive use of global objects in the program will greatly reduce the robustness, stability, maintainability and reusability of the program. C + + can also completely eliminate the global object, but ultimately no, I think one of the reasons is to be compatible with C.

Second, static members of the class, as mentioned above, all objects of the base class and its derived classes share this static member object, so this static member is a good choice when it is necessary to share or communicate data between these classes or between these class objects.

Then there is the static local object, which can be used primarily to hold the middle state of the function that the object is in for repeated invocations, one of the most notable examples being recursive functions, we all know that recursive functions call their own functions, and if a nonstatic local object is defined in a recursive function, So when the number of recursion is quite large, the overhead is huge. This is because the nonstatic local object is a stack object, once per recursive invocation, an object such as this is generated, and each time it is returned, the object is released, and such objects are limited to the current call layer, and are invisible to the deeper nesting layer and the Salu outer layer. Each layer has its own local objects and parameters.

In the design of a recursive function, a static object can be used instead of a nonstatic local object (that is, a stack object), which not only reduces the overhead of generating and releasing nonstatic objects on each recursive call and return, but also the static object can hold the middle state of a recursive call, and can be accessed for each call layer.

Unexpected harvesting of 3.1.3 using stack objects

As described earlier, the Stack object is created at the appropriate time, and then automatically released at the appropriate time, that is, the stack object has the automatic management function. Then the Stack object will be automatically released in what. First, at the end of its life period, and secondly, when the function in which it is located is abnormal. You might say, these are all normal, no big deal. Yes, it's no big deal. But as long as we go a little deeper, maybe there will be an unexpected harvest.

Stack object, which, when automatically released, invokes its own destructor. If we encapsulate the resource in the Stack object and perform the action of releasing the resource in the destructor of the stack object, the probability of the resource leak will be greatly reduced because the stack object can automatically release the resource, even when the function is abnormal. The actual process is this: when a function throws an exception, the so-called stack_unwinding (stack rollback) occurs, that is, the stack expands, because the stack object is naturally present in the stack, so the destructor of the stack object is executed during the stack rollback, freeing its encapsulated resources. Unless, unless you throw the exception again during the execution of the destructor-and this possibility is small-it is safe to encapsulate the resource with the Stack object. Based on this knowledge, we can create one of our own handles or proxies to encapsulate resources. This technique is used in the smart pointer (auto_ptr). In the case of this need, we want our resource encapsulation class to be created only on the stack, which is to restrict the creation of instances of the resource encapsulation class in the heap.

3.1.4 prevents heap objects from being generated

As mentioned above, you decide to prohibit the generation of some type of heap object, at which point you can create a resource encapsulation class that can only be generated on the stack so that the encapsulated resources can be automatically freed in exceptional circumstances.

So how to prohibit the generation of heap objects. We already know that the only way to generate a heap object is to use the new operation, and if we prohibit the use of new it is OK. Further, the new operation will invoke operator new when it executes, and operator new can be overloaded. Method has, is to make new operator private, in order to symmetry, it is best to operator delete also overload for private. Now that you may have questions, isn't it necessary to create a stack object without calling new? Yes, no, because creating a stack object does not require searching for memory, but instead directly adjusts the stack pointer and pushes the object stack, the main task of operator new is to search for the right heap memory and allocate space for the heap objects, as mentioned above. OK, let's take a look at the following sample code: #include <stdlib.h>//C-type memory allocation function required

Class Resource; Represents a resource class that needs to be encapsulated
Class Nohashobject
{
Private
resource* ptr;//point to encapsulated resource
.../Other data members
void* operator new (size_t size)//not strictly implemented, only for schematic purposes
{
return malloc (size);
}

void operator Delete (void* pp)//not strictly implemented, only for schematic purposes
{
Free (PP);
}

Public
Nohashobject ()
{
Here you can get the resources you need to encapsulate and have the PTR pointer point to the resource
ptr = new Resource ();
}

~nohashobject ()
{
Delete ptr; Releasing the encapsulated resource

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.