Trend technology's interview questions:
Please refer to the following program to explain what problems will happen?
# Include <iostream>
# Include <cstdlib>
# Include <vector>
Using namespace STD;
Class cdemo {
Public:
Cdemo (): STR (null ){};
~ Cdemo ()
{
If (STR) Delete [] STR;
};
Char * STR;
};
Int main (INT argc, char ** argv ){
Cdemo D1;
D1.str = new char [32];
Strcpy (d1.str, "Trend Micro ");
Vector <cdemo> * a1 = new vector <cdemo> ();
A1-> push_back (D1 );
Delete A1;
Return exit_success;
}
When this program exits, there will be a problem. What is the problem? The program crashes when the same piece of memory is deleted repeatedly.
Let's change the destructor to the following:
~ Cdemo ()
{
If (STR)
{
Static int I = 0;
Cout <"& cdemo" <I ++ <"=" <(int *) This <", STR =" <(int *) STR <Endl;
Delete [] STR;
}
};
The following information is printed during running:
& Amp; cdemo0 = 000309d8, STR = 000307a8
& Amp; cdemo1 = 0013ff70, STR = 000307a8
That is to say, the cdemo class occurs twice, and the two Destructors point to the same memory address space (the two STR values are the same = 000307a8 ).
Why?
The second version of the programmer's interview book, P99, has an explanation: "The vector Object Pointer can be automatically analyzed, so you do not need to call Delete A1; otherwise, two destructed objects will be generated"
I thought this sentence was a bit inappropriate. If any object has applied for space through the new operator, it must be displayed and deleted by calling Delete. Therefore, the "delete A1;" statement is correct.
In this sentence, "vector <cdemo> * a1 = new vector <cdemo> ();" sets a pointer to vector <cdemo>. The new operator is used for initialization, we must release the memory space occupied by A1. therefore, the "delete A1;" statement is correct. In addition, we must understand that, to release a vector object, the elements contained in the vector are also released.
Is there an error?
The A1 statement and the initialization statement "vector <cdemo> * a1 = new vector <cdemo> ();" indicate that the elements contained in A1 are of the "cdemo" type, when executing the statement "A1-> push_back (D1);", the copy constructor of cdemo is called. Although the copy constructor is not defined in the cdemo class, however, the compiler will build a default copy constructor (Shortest copy) for the cdemo class. This is like if no constructor is defined for any object, the compiler will build a default constructor.
This is exactly the case. STR member variables of all cdemo elements in A1 are not initialized, and there is only one four-byte (32-bit) pointer space.
"A1-> push_back (D1);" after execution, the cdemo element in A1 is different from that in D1, however, STR and d1.str of the cdemo element in A1 point to the same memory, which can be seen from the printed information later.
We know that local variables, such as "cdemo D1;", automatically release the occupied memory space when the main function exits,
The cdemo destructor "~ Cdeme ", the problem lies here.
The previous "delete A1;" has released d1.str (because STR and d1.str of the cdemo element in A1 point to the same memory). When the main function exits, the released d1.str memory space is released, so the program crashes.
The explanation is clear.
The core issue here is in the final analysis the issue of shallow copy and deep copy. If such a copy constructor is added to the cdemo class, the problem can be solved:
Cdemo (const cdemo & CD)
{
This-> STR = new char [strlen (CD. Str) + 1];
Strcpy (STR, CD. Str );
};
This is the deep copy.
Or use the following code:
Vector <cdemo *> * a1 = new vector <cdemo *> ();
A1-> push_back (& D1 );
Then, when "delete A1;" A1 is released, the elements contained in A1 ("cdemo *" type, still a pointer, 4 bytes space ).Deep copy:A shallow copy is a one-to-one value assignment between member data: assign values to the values to be copied. However, there may be a situation where the object also contains resources. The resources here can be a heap resource or a file .. When the value is copied, the two objects use the same resources and can access the resources, which leads to problems. Deep copy is used to solve this problem. It also assigns resources once so that objects have different resources, but the content of resources is the same. For heap resources, a heap memory is being opened to copy the original content. If the object you copied references an external content (such as the Data allocated to the stack), let the new and old objects point to the same external content when copying the object, it is a shortest copy. If an independent copy of an external object is created for the new object when the object is copied, the deep copy reference is similar to the pointer semantics, and the reference is an unchangeable pointer, pointer is a changeable reference. The reference semantics is actually implemented.
The difference between deep copy and shallow copy is that when the object State contains references from other objects, when copying an object, if you need to copy the object referenced by this object, it is a deep copy, otherwise, it is a shortest copy. Cow semantics is a combination of "Deep copy" and "Deferred computing". It is still a deep copy, not a shallow copy, because the data of the two objects after the copy is logically irrelevant, the content is the same. It is required regardless of the depth. When a deep copy occurs, it usually indicates that there is an "aggregation relationship", while when a shallow copy occurs, it usually indicates that there is a "acquaintance relationship ".
A simple example:
When you implement a composite pattern, you usually implement a deep copy (if you need to copy it), and few require the same composite to share leaf;
When you implement an observer pattern, if you need to copy the observer, you probably won't copy the subject, then you need to implement a shortest copy.
Whether it is a deep copy or a shallow copy does not depend on time efficiency, space efficiency, or language, but on which one is logically correct.