Usage of default copy functions in c ++

Source: Internet
Author: User

In c ++ programming ideology, if a class does not copy a function, the compiler automatically creates a default copy function. Next let's take a look at the real situation.

First, let's look at a simple Class X, which does not display the definition of the copy constructor.

C ++ source code is as follows:

Copy codeThe Code is as follows: class X {
Private:
Int I;
Int j;
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

The following is the assembly code:
Copy codeThe Code is as follows: _ main PROC

; 7: int main (){

Push ebp
Mov ebp, esp
Sub esp, 16; reserved 16 bytes of stack space for objects x1 and x2

; 8: X x1; // first defines the object x1
; 9: X x2 = x1; // copy x1 to x2

Mov eax, dword ptr _ x1 $ [ebp]; give the content in the first address of x1 to the Register eax, and then assign the value of member variable I in x1 to eax
Mov dword ptr _ x2 $ [ebp], eax; write the value in eax to the first address of x2, that is, write the value in eax to member variable I of x2
Mov ecx, dword ptr _ x1 $ [ebp + 4]; the value in the memory at the first 4 bytes of the x1 offset is sent to the Register eax, that is, the value of member variable j in x1 is given to ecx.
Mov dword ptr _ x2 $ [ebp + 4], ecx; write the values in ecx into the memory at the 4byte address of the Offset x2, that is, write the value in ecx to the member variable j of x2.

; 10 :}

Xor eax, eax
Mov esp, ebp
Pop ebp
Ret 0
_ Main ENDP

From the assembly code, we can see that no function is called at all, and all the copy assignments are completed through communication between registers and memory addresses. Like the default constructor provided by the compiler, this situation can be viewed as a useless copy constructor provided by the compiler.

So when will the compiler actually provide the default copy constructor and display the call?

The following is a case where class X contains virtual member functions:

C ++ source code:

Copy codeThe Code is as follows: class X {
Private:
Int I;
Int j;
Public:
Virtual ~ X () {}// virtual destructor
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

Since we only discuss the copy function here, we only look at the assembly code in the main and copy functions:

The following is the assembly code in the main function:

Copy codeThe Code is as follows: _ main PROC

; 9: int main (){

Push ebp
Mov ebp, esp
Sub esp, 24; because of the introduction of virtual functions, each class occupies space programming 12 byte member variable I, j8byte vptr pointer 4 byte so here we reserve 24 byte for x1 x2

; 10: X x1; // first define the object x1

Lea ecx, dword ptr _ x1 $ [ebp]; get the first address of x1 and put it in ecx. It is passed in to the secret parameter that calls the constructor, that is, this
Call ?? 0X @ QAE @ XZ; call the constructor

; 11: X x2 = x1; // copy x1 to x2

Lea eax, dword ptr _ x1 $ [ebp]; get the first address of x1 and put it in the register eax
Push eax; press the eax stack as a parameter for copying Constructors
Lea ecx, dword ptr _ x2 $ [ebp]; get the first address of x2 and put it into the register ecx as the secret parameter for calling the copy constructor, that is, this
Call ?? 0X @ QAE @ ABV0 @ Z; call the copy constructor

; 12 :}

Lea ecx, dword ptr _ x2 $ [ebp]; get the first address of x2 and put it in the ecx register as the secret parameter passed in by calling the destructor, that is, this
Call ?? 1X @ UAE @ XZ; call the destructor
Lea ecx, dword ptr _ x1 $ [ebp]; get the first address of x1 and put it in the ecx register as the secret parameter passed in by calling the destructor, that is, this
; The order of the analysis structure is opposite to that of the build
Call ?? 1X @ UAE @ XZ; call the destructor
Xor eax, eax
Mov esp, ebp
Pop ebp
Ret 0
_ Main ENDP

As you can see, the compiler provides default copy constructor (non-Useless default copy constructor) for Class X and displays the call.

Because a class inherits from the virtual base class or the base class that inherits its own virtual function members, it also contains virtual function members. Therefore, it belongs to the previous situation. In this case, the compiler also provides non-Useless default copy constructor and displays the call.

The following is the second case. Class X inherits from class Y. Class Y has a copy constructor that is displayed and defined, but the class does not provide a copy constructor:

The following is the c ++ source code:

Copy codeThe Code is as follows: class Y {
Private:
Int j;
Public:
Y (const Y & y ){}
Y () {}; // The default constructor must be provided for Y; otherwise, the compilation fails.
};
Class X: public Y {
Private:
Int I;
Int j;
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

The following is the compilation code of the mian function:Copy codeCode:; 16: int main (){

Push ebp
Mov ebp, esp
Sub esp, 24; reserved 24 byte space for x1 x2

; 17: X x1; // first defines the object x1

Lea ecx, dword ptr _ x1 $ [ebp]; obtain the first address of x1 and pass it as an implicit parameter to the constructor.
Call ?? 0X @ QAE @ XZ; // call the default constructor provided by the compiler for Class X

; 18: X x2 = x1; // copy x1 to x2

Lea eax, dword ptr _ x1 $ [ebp]; get the first address of x1 and pass it to the Register eax
Push eax; press the eax stack as a parameter to call the copy constructor of Class X
Lea ecx, dword ptr _ x2 $ [ebp]; obtain the first address of x2 as an implicit parameter for calling the copy function of Class X
Call ?? 0X @ QAE @ ABV0 @ Z; call the default copy constructor provided by the compiler.

; 19 :}

Xor eax, eax
Mov esp, ebp
Pop ebp
Ret 0

The following is the assembly code of the copy constructor of Class X:Copy codeThe Code is as follows :?? 0X @ QAE @ ABV0 @ z proc; X: X, COMDAT
; _ This $ = ecx
Push ebp
Mov ebp, esp
Push ecx
Mov dword ptr _ this $ [ebp], ecx; ecx contains the first address of x2
Mov eax, dword ptr ___ that $ [ebp]; give the first address of x1 to eax
Push eax; press the first address of eax to the stack as a parameter for calling the copy constructor of the parent class
Mov ecx, dword ptr _ this $ [ebp]; send the first address of x2 to ecx as an implicit parameter to the copy constructor of the parent class.
Call ?? 0Y @ QAE @ ABV0 @ Z; call the parent class copy constructor
Mov ecx, dword ptr _ this $ [ebp]; get the first address of x2 to ecx
Mov edx, dword ptr ___ that $ [ebp]; get the first address of x1 to edx
Mov eax, dword ptr [edx + 4]; write the value in the memory at the first 4 bytes of the Offset x1 to eax, that is, write the value of the subclass member variable I in x1 to eax, because the first address of x1 stores the parent class member variable I, its value
The parent class copy constructor is responsible for copying to x2
Mov dword ptr [ecx + 4], eax; write the value of eax into the memory at 4 bytes away from the x2 first address, that is, write the value of eax into the sub-class member variable I in x2, because the first address of x2 stores the parent class member variable I, its value
The parent copy constructor is responsible for copying
Mov ecx, dword ptr _ this $ [ebp]; give the first address of x2 to ecx
Mov edx, dword ptr ___ that $ [ebp]; give the first address of x1 to edx
Mov eax, dword ptr [edx + 8]; returns the value in the memory at 8 bytes at the first address of x1 to eax, that is, the value of the subclass member variable j in x1 is given to eax
Mov dword ptr [ecx + 8], eax; writes the eax value to the memory at the 8-byte first address of the Offset x2, and writes the eax value to the member j of the x2 subclass.
Mov eax, dword ptr _ this $ [ebp]; returns the first address of x2 to eax. The constructor always returns the first address of the object.
Mov esp, ebp
Pop ebp
Ret 4
?? 0X @ QAE @ ABV0 @ Z ENDP

From the assembly code, we can see that the compiler indeed provides the default copy constructor for Class X and makes a display call. In addition, when calling the copy constructor of Class X, first call the copy constructor of the parent class, copy the member variables in the parent class, and then copy the member variables in the subclass.

The copy constructor assembly code in the parent class Y is as follows:

Copy codeThe Code is as follows :?? 0Y @ QAE @ ABV0 @ z proc; Y: Y, COMDAT
; _ This $ = ecx

; 5: Y (const Y & y ){}

Push ebp
Mov ebp, esp
Push ecx; // the stack is pushed to this (the first address of x2) That is implicitly passed to the copy function of the parent class)
Mov dword ptr _ this $ [ebp], ecx; ecx contains the first address (this) of x2, which is placed in the reserved space
Mov eax, dword ptr _ this $ [ebp]; writes the first address of x2 to eax as the return value. The constructor always returns the first address of the object.
Mov esp, ebp
Pop ebp
Ret 4
?? 0Y @ QAE @ ABV0 @ z endp; Y: Y
_ TEXT ENDS

From the Assembly, we can see that since the parent class itself displays and defines the copy constructor, the compiler is only responsible for calling and does not provide the copy function of the constructor by default in the subclass X above, that is, the parent class member variable I is not copied. In the c ++ source code, the parent class copy constructor itself is an empty function and does nothing.

If neither the subclass X parent class Y provides a copy constructor, what is the situation sometimes?

The following is the c ++ source code:

Copy codeThe Code is as follows: class Y {
Private:
Int j;
};
Class X: public Y {
Private:
Int I;
Int j;
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

The following is the corresponding assembly code:Copy codeThe Code is as follows: _ main PROC

; 12: int main (){

Push ebp
Mov ebp, esp
Sub esp, 24; reserved 24 byte space for x1 x2

; 13: X x1; // first define the object x1
; 14: X x2 = x1; // copy x1 to x2

Mov eax, dword ptr _ x1 $ [ebp]; get the value in the first address of x1 and save it to eax. That is, get the value of x1 parent class member variable I and write it to eax.
Mov dword ptr _ x2 $ [ebp], eax; write the eax value to the memory pointed to by the first address of x2, that is, write the eax value to the parent class member variable I in x2
Mov ecx, dword ptr _ x1 $ [ebp + 4]; get the value in the memory at the 4byte first address of the x1 offset, and write it to ecx, obtain the value of member variable I of the x1 subclass and write it to ecx.
Mov dword ptr _ x2 $ [ebp + 4], ecx; write the ecx value to the memory at the 4byte address at the first address of the Offset x2, and write the ecx value to the member variable I of the Child class in x2
Mov edx, dword ptr _ x1 $ [ebp + 8]; get the value in the memory at 8 byte at the first address of x1 offset, and write it to edx, get the value of member j of the x1 subclass and write it to edx.
Mov dword ptr _ x2 $ [ebp + 8], edx; write the edx value to the memory at 8 bytes at the first address of the Offset x2, and write the edx value to the member variable j of the x2 subclass.

; 15 :}

Xor eax, eax
Mov esp, ebp
Pop ebp
Ret 0
_ Main ENDP

As you can see, the compiler executes the copy process, but provides useless default copy constructor at the beginning, whether it is copying the parent class member variable or subclass member variable, no function calls.

In the third case, Class X contains member variables of class Y. member variables of class Y include copy constructors.

C ++ source code is as follows:

Copy codeThe Code is as follows: class Y {
Private:
Int j;
Public:
Y (const Y & y ){}
Y () {} // The default constructor must be provided for Y; otherwise, an error is returned during compilation.
};
Class X {
Private:
Int I;
Int j;
Y y;
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

The assembly code in the main function is as follows:
Copy codeThe Code is as follows: _ main PROC

; 16: int main (){

Push ebp
Mov ebp, esp
Sub esp, 24; reserved 24 byte space for x1 x2

; 17: X x1; // first defines the object x1

Lea ecx, dword ptr _ x1 $ [ebp]; obtain the first address of x1 and pass it as an implicit parameter to the constructor.
Call ?? 0X @ QAE @ XZ; call the constructor

; 18: X x2 = x1; // copy x1 to x2

Lea eax, dword ptr _ x1 $ [ebp]; get the first address of x1 and put it in the register eax
Push eax; press the eax stack and pass it as a parameter to the default copy constructor provided by the compiler
Lea ecx, dword ptr _ x2 $ [ebp]; obtain the first address of x2 and pass it as an implicit parameter to the default copy constructor provided by the compiler.
Call ?? 0X @ QAE @ ABV0 @ Z; call the copy constructor

; 19 :}

Xor eax, eax
Mov esp, ebp
Pop ebp
Ret 0
_ Main ENDP

The following is the assembly code of the default copy constructor provided by the compiler for Class X:Copy codeThe Code is as follows :?? 0X @ QAE @ ABV0 @ z proc; X: X, COMDAT
; _ This $ = ecx
Push ebp
Mov ebp, esp
Push ecx; the purpose of the stack is to reserve space for this (the first address of x2 ).
Mov dword ptr _ this $ [ebp], ecx; ecx contains the first address of x2, which is placed in the space reserved just now.
Mov eax, dword ptr _ this $ [ebp]; give the first address of x2 to eax
Mov ecx, dword ptr ___ that $ [ebp]; give the first address of x1 to ecx
Mov edx, dword ptr [ecx]; write the content of the first address of x1 to edx, that is, write the member variable I in x1 to edx
Mov dword ptr [eax], edx; write the value of edx to the first address of x2, that is, write the value of edx to the member variable I of x2
Mov eax, dword ptr _ this $ [ebp]; write the first address of x2 to the Register eax
Mov ecx, dword ptr ___ that $ [ebp]; write the first address of x1 into the register ecx
Mov edx, dword ptr [ecx + 4]; write the value in the memory at the 4byte first address of x1 to edx, that is, write the value of member variable j of x1 to edx
Mov dword ptr [eax + 4], edx; write the value of edx to the memory at the 4byte offset x2 first address, that is, write the value of edx to the member variable j of x2
Mov eax, dword ptr ___ that $ [ebp]; store the first address of x1 into the register eax
Add eax, 8; // add the first address of x1 to 8, get the address of member object y in x1, and put it in eax
Push eax; apply the eax value to the stack as a parameter for calling the copy function of member variable y
Mov ecx, dword ptr _ this $ [ebp]; store the first address of x2 into the register ecx
Add ecx, 8; add the first address of x2 to 8, get the address of member object y in x2, and put it in ecx. This address is used as an implicit parameter and passed to the copy constructor of the member variable function.
Call ?? 0Y @ QAE @ ABV0 @ Z; call the copy constructor of member object y.
Mov eax, dword ptr _ this $ [ebp]; put the first address of x2 into eax as the return value. The constructor always returns the first address of the object.
Mov esp, ebp
Pop ebp
Ret 4
?? 0X @ QAE @ ABV0 @ Z ENDP

From the Assembly, we can see that when calling the Class X to copy the constructor, we first copy the member variables I and j in x1 to x2, then, the member variable in y is copied by calling the copy constructor of member object y. This is different from inheritance. in inheritance, the copy constructor of the parent class is always called before copying in the subclass. This shows that, for such a situation that contains Member objects, the call time of the member object's copy function is related to the position they define. Here, the member object y of Class X is defined after member variables I and j. Therefore, its copy constructor will be called only after I is copied and j is completed.

The following is the assembly code of the copy constructor in class Y:

Copy codeThe Code is as follows :?? 0Y @ QAE @ ABV0 @ z proc; Y: Y, COMDAT
; _ This $ = ecx

; 6: Y (const Y & y ){}

Push ebp
Mov ebp, esp
Push ecx; the pressure stack ecx is designed to store this (the first address of member object y in x2) reserved space
Mov dword ptr _ this $ [ebp], ecx; ecx contains the first address of member object y in x2, which is placed in the reserved space just now
Mov eax, dword ptr _ this $ [ebp]; put the first address of the member variable in x2 into eax as the return value. The constructor always returns the first address of the object.
Mov esp, ebp
Pop ebp
Ret 4
?? 0Y @ QAE @ ABV0 @ Z ENDP

As you can see from the code, because class Y displays the definition of the copy constructor, the compiler is only responsible for displaying the call and does not provide any copy function. In class Y, the copy constructor is defined as an empty function.

What if the member object does not copy the constructor like inheritance?

The following is the c ++ source code:

Copy codeThe Code is as follows: class Y {
Private:
Int j;

};
Class X {
Private:
Int I;
Int j;
Y y;
};

Int main (){
X x1; // first define the object x1
X x2 = x1; // copy x1 to x2
}

The following is the object assembly code:
Copy codeThe Code is as follows: _ main PROC

; 14: int main (){

Push ebp
Mov ebp, esp
Sub esp, 24; 00000018 H

; 15: X x1; // first define the object x1
; 16: X x2 = x1; // copy x1 to x2

Mov eax, dword ptr _ x1 $ [ebp]; write the content of the first address in x1 to eax, that is, write the value of the member variable in x1 to eax
Mov dword ptr _ x2 $ [ebp], eax; write the eax value to the first address of x2, that is, write the eax value to the member variable I of x2
Mov ecx, dword ptr _ x1 $ [ebp + 4]; write the content in the memory at the 4byte offset of x1 to ecx, that is, write the value of member variable j in x1 to ecx
Mov dword ptr _ x2 $ [ebp + 4], ecx; write the ecx value to the memory at the 4byte address at the first address of the Offset x2, that is, write the ecx value to the member variable j in x2
Mov edx, dword ptr _ x1 $ [ebp + 8]; write the memory value at the 8-byte offset from the first address of x1 member object y to edx, write the I value of member variable in member object y in x1 to edx
Mov dword ptr _ x2 $ [ebp + 8], edx; write the edx value to the memory at the 8-byte offset of x2 first address (here is the first address of x2 member object y, write the edx value to member variable I of member object y in x2

Can we see from the Assembly that, in this case, the compiler simply provides useless default copy constructor, that is, function calls that are not displayed, but only completes the copy process through communication between registers and memory?

Based on the above analysis, we can see that:

For a class, if it does not display a definition copy constructor, the compiler does not always provide a non-Useless default copy constructor unless:

1This class contains virtual function member functions (including virtual function members inherited from the virtual base class or inherited base class). In this case, the compiler provides a non-Useless default copy constructor for this class.

2This class inherits from a base class, and the base class contains a custom copy function. In this case, the compiler provides a non-Useless default copy constructor for this class. (This is also the case if the base class itself does not define a copy constructor, but the compiler provides a non-Useless default copy constructor for the base class. That is to say, the base class only needs to contain a non-Useless copy constructor, whether the non-Useless copy constructor is customized or provided by the compiler)

3This class contains a member object, which has a custom copy constructor. In this case, the compiler provides a non-Useless default copy constructor for this class. (This is also the case if the member object itself does not define a copy constructor, but the compiler will provide a non-Useless default copy constructor for the member object. That is to say, a member object only needs to contain a non-Useless copy constructor. no matter whether the non-Useless copy constructor is customized, it is provided by the compiler. This is similar to the previous one ).

In addition, if a class customizes a copy constructor, the compiler is only responsible for calling and does not provide any additional copy process. For the default copy function provided by the compiler, it is useless, it is not useless. It is only a bit copy (that is, a shallow copy ).

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.