Prohibit heap object generation
As mentioned above, you have decided to prohibit the generation of some type of heap objects. In this case, you can create a resource encapsulation class by yourself, which can only be generated in the stack, in this way, the encapsulated resources can be automatically released in case of exceptions.
So how can we disable heap objects? We already know that the only way to generate heap objects is to use the new operation. If we do not allow the use of the new operation, it will be okay. Furthermore, operator new is called when the new operation is executed, and operator new can be reloaded. The new operator is private. For symmetry, it is best to reload operator Delete to private. Now, you may have another question. Do you not need to call new to create a stack object? Yes, no, because creating stack objects does not need to search for memory. Instead, you can directly adjust the stack pointer and press the object onto the stack. The main task of operator new is to search for the appropriate heap memory, allocate space for heap objects, as mentioned above. Okay. Let's take a look at the following sample code:
# Include <stdlib. h> // The C-type memory allocation function is required. Class resource; // indicates the resource class to be encapsulated. Class nohashobject { PRIVATE: Resource * PTR; // point to the encapsulated Resource ... // Other data member Void * operator new (size_t size) // non-strict implementation, for illustration only { Return malloc (size ); } Void operator Delete (void * PP) // not strictly implemented, for illustration only { Free (PP ); } Public: Nohashobject () { // Obtain the resources to be encapsulated and point the PTR pointer to the resource. PTR = new resource (); } ~ Nohashobject () { Delete PTR; // release encapsulated Resources } }; |
Nohashobject is now a class for prohibiting heap objects. If you write the following code:
Nohashobject * fp = new nohashobject (); // compilation error! Delete FP; |
The above code produces a compilation error. Now that you know how to design a class to prohibit heap objects, you may have the same question as me. Is it possible that the definition of Class nohashobject cannot be changed, will it be impossible to generate heap objects of this type? No, there is still a solution. I call it "brute-force cracking ". C ++ is so powerful that you can use it to do whatever you want. The technique used here is the forced conversion of pointer types.
Void main (void) { Char * temp = new char [sizeof (nohashobject)]; // Force type conversion. Now PTR is a pointer to the nohashobject object. Nohashobject * obj_ptr = (nohashobject *) temp; Temp = NULL; // prevents the nohashobject object from being modified through the temp pointer // Force type conversion again to direct the RP pointer to the PTR Member of the nohashobject object in the heap Resource * Rp = (resource *) obj_ptr; // Initialize the PTR Member of the nohashobject object pointed to by obj_ptr Rp = new resource (); // Now you can use the obj_ptr pointer to use the nohashobject object member in the heap. ...... Delete RP; // release resources Temp = (char *) obj_ptr; Obj_ptr = NULL; // prevents pointer Suspension Delete [] temp; // release the heap space occupied by the nohashobject object. } |
The above implementation is troublesome, and this implementation method is almost never used in practice, but I still write the path, because I understand it, it is good for us to understand C ++ memory objects. What is the most fundamental of the above forced type conversion? We can understand this as follows:
The data in a piece of memory remains unchanged, and the type is the glasses we wear. When we wear a pair of glasses, we will use the corresponding types to explain the data in the memory, in this way, different interpretations get different information.
The so-called forced type conversion is actually to replace another pair of glasses and then look at the same memory data.
In addition, it should be noted that different compilers may have different layout arrangements for object member data, for example, most compilers arrange the PTR pointer member of nohashobject In the first 4 bytes of the object space to ensure that the conversion action of the following statement is executed as expected:
Resource * Rp = (resource *) obj_ptr; |
However, not all compilers do.
Since we can prohibit the generation of some type of heap objects, can we design a class so that it cannot generate STACK objects? Of course.
Stack object generation prohibited
As mentioned above, when a stack object is created, the top pointer of the stack is moved to a space of an appropriate size, then, the corresponding constructor is called directly in this space to form a stack object. When the function returns, the corresponding constructor is called to release the object, then adjust the stack top pointer to reclaim the stack memory. In this process, the operator new/delete operation is not required. Therefore, setting operator new/Delete to private cannot be achieved. Of course, from the above description, you may have thought of setting the constructor or destructor as private so that the system cannot call the constructor or destructor, of course, you cannot generate objects in the stack.
This is indeed true, and I plan to adopt this solution. But before that, we need to make it clear that if we set the constructor to private, we cannot use new to directly generate heap objects, because New will also call its constructor After allocating space for the object. Therefore, I plan to only set the destructor to private. In addition to limiting the generation of stack objects, does setting the Destructor private affect the generation of stack objects? Yes, this also limits inheritance.
If a class is not intended as a base class, the usual solution is to declare its destructor as private.
To restrict stack objects without limiting inheritance, we can declare the Destructor as protected, so that the two are both beautiful. The following code is used:
Class nostackobject { Protected: ~ Nostackobject (){} Public: Void destroy () { Delete this; // call to protect destructor } }; |
Next, you can use the nostackobject class as follows:
Nostackobject * hash_ptr = new nostackobject (); ... // Operate on the object pointed to by hash_ptr Hash_ptr-> destroy (); |
Haha, isn't it a little strange? We use new to create an object, but not delete it, but use the destroy method. Obviously, users are not used to this weird method of use. So I decided to set the constructor to private or protected. This goes back to the problem that we tried to avoid, that is, we don't need new. How can we generate an object? We can do this indirectly by providing a static member function for this class to generate heap objects of this type. (The Singleton mode in the design mode can be implemented in this way .) Let's take a look:
Class nostackobject { Protected: Nostackobject (){} ~ Nostackobject (){} Public: Static nostackobject * creatinstance () { Return new nostackobject (); // call the protected Constructor } Void destroy () { Delete this; // call the protected destructor } }; |
Now we can use the nostackobject class as follows:
Nostackobject * hash_ptr = nostackobject: creatinstance (); ... // Operate on the object pointed to by hash_ptr Hash_ptr-> destroy (); Hash_ptr = NULL; // prevents pointer Suspension |
Now it feels better. The operations for generating and releasing objects are the same.