Construction operation of 2.2 Copy Constructor
There are three cases in which the content of one object is used as the initial value of another class object, one of the most obvious cases is an explicit initialization of an object, such as the following:
Class X {...}; X x;//explicitly takes the contents of an object as the initial value of another class object x xx = x;
The other two cases are when an object is given to a function as a parameter, for example
extern void foo (x x); void Bar () { x xx; Take XX as the initial value of the first parameter (implicit initialization operation) foo (xx);}
And when the function returns a class object. For example:
x Foo_bar () { x xx; return xx;}
Suppose the Class designer explicitly defines a copy constructor (this is a constructor, and the type of one parameter is its class type), for example:
User-defined copy Constructor instance//Can be a multi-parameter form, its second parameter and subsequent parameters are supplied with a default value of x::x (const X &x); Y::y (const Y &y, int = 0);
In most cases, the above constructor will be called when a class object is used as the initial value for another homogeneous entity. This may result in a transient class object generation or program code metamorphosis.
Default memberwise Initialization What happens if class doesn't provide a explicit copy constructor?
When class object takes "another object of the same class" as the initial value,The
interior is done with the so-called default memberwise initialization, that is, the value of each built-in or derived data member (such as a pointer or an array), from one object to another object, However, it does not copy the Member class object, but instead memberwise the initialization in a recursive manner. For example, consider the following class declaration:
Class String {public: //... No explicit copy constructorprivate: char *str; int Len;};
The default memberwise initialization of a string object occurs in this case:
String noun ("book"); String verb = noun; The way it is done is like setting each of the members individually: VERB.STR = Noun.str;verb.len = Noun.len;
If a string object is declared as the member of another class, as follows:
Class Word {public: //... No explicit copy constructorprivate: int _occurs; String _word; String object becomes a member} of class Word;
Then a Word object's default memberwise initialization will copy the built-in member _occurs, and then recursively implement member from string _word object memberwise Initialization.
How does such an operation actually be done? Arm noted:
Conceptually, for a class X, this operation is implemented by a copy constructor.
The key is "conceptually," and the note follows some explanations:
A good compiler can generate bitwise copies for most class objects because they have bitwise copy semantics ...
That is, "If a class does not define a copy constructor, the compiler will automatically generate a" this sentence is not correct, but should be like arm said:
The Default constructors and copy constructors are generated when necessary by the production compiler.
The "necessity" of this sentence refers to when class does not show bitwise copy semantics. The C + + standard still retains the meaning of arm, but the discussion is more formalized as follows:
A class object can be copied in two ways, one is initialized and the other is specified (Assignment). Conceptually, these two operations are done with the copy constructor and copy assignment operator, respectively.
Just like default constructor, C + + standard states that if class does not declare a copy constructor, an implicit declaration appears. C + + Standard to distinguish copy constructor as trivial and nontrivial two, only the nontrivial entity will be synthesized in the program, determine whether a copy constructor is trivial is Does the class show the so-called "bitwise copy Semantics".
Bitwise copy semantics (bit successive copy) in the following program fragment:
#include "Word.h" word noun ("book"), void foo () { word verb = noun;}
It is obvious that verb is initialized according to noun, but it is not possible to predict the program behavior of this initialization operation until the class word declaration has been seen, if the designer of class word has defined a copy Constructor,verb initialization operation to invoke it. But if the class does not have a explicit copy constructor defined, will a compiler-synthesized entity be called? This depends on whether the class shows "bitwise copy Semantics". As shown below:
The following statement shows the bit copy semanticsclass Word {public: word (const char *); ~word () { delete []str; } Private: int cnt; char *str;};
In this case, there is no need to synthesize a default copy constructor, because the above declaration shows "default copy semantics", so verb initialization does not require a function call, however, if the class Word is declared like this:
The following statement does not show bitwise copy Semanticsclass Word {public: word (const String &); ~word ();p rivate: int cnt; String str;}; Where string declares a explicit copy Constructor:class string {public: string (const char *); String (const string &); ~string ();};
In this case, the compiler must synthesize a copy constructor to invoke the copy constructor of the member class String object:
A crafted copy constructor//C + + pseudo-code inline Word::word (const Word &WD) { str. String::string (WD.STR); CNT = wd.cnt;}
It is worth noting that in this synthesized copy constructor, Nonclass members, such as integers, pointers, arrays, and so on, are also copied.
Do not bitwise copy semantics
when does a class not show "bitwise copy Semantics"? There are four types of cases:
1. When class contains a member object and the latter's class declaration has a copy constructor (either explicitly declared by the class Designer or synthesized by the compiler)
2. When class inherits from a base class and then exists with a copy constructor
3. When class declares one or more virtual functions
4. When class derives from an inherited chain, there is one or more virtual base classe
In the first two cases, the compiler must insert the "Copy constructors Invoke action" of the members or base class into the synthesized copy constructor. The latter two situations are a bit complicated, as described in the next section.
Reset the pointer to Virtual table
Two program expansion operations during compilation (as long as one class declares one or more virtual functions):
Add a virtual function table (VTBL) that contains the address of each function virtual function
Inserts a pointer to Virtual funtcion table (vptr) into each class object
Obviously, if the compiler does not successfully set its initial value correctly for each new class object vptr, it will have dire consequences. Therefore, when the compiler imports a vptr into class, the class will no longer show bitwise semantics. Now the compiler needs to synthesize a copy constructor to vptr appropriate initialization, as follows:
First, define two classes,zooanimal and bear
Class Zooanimal {public: zooanimal (); Virtual ~zooanimal (); virtual void animate (); virtual void Draw ();p rivate: //Zooanimal animate () and draw () //Required data};class bear:public zooanimal {public: Bear (); void Animate (); void Draw (); virtual void Dance ();p rivate: //Bear animate () and draw () and dance () //Required data};
Zooanimal class object takes another Zooanimal class object as the initial value, or the Bear class object takes another bear class object as the initial value, which can be directly dependent on the bitwise copy Semantics "completed. For example:
Bear Yogi; Bear Winnie = Yogi;
Yogi will be initialized by default bear constructor, and in constructor, Yogi's VTPR is set to virtual table for bear class. Therefore, to copy the vptr value of Yogi to Winnie Vptr is complete.
When a base class object is initialized with its derived class content, its vptr copy operation must also be secure, for example:
Zooanimal Franny = Yogi; This will occur when cutting (sliced)
Franny's vptr cannot be set to virtual table of the Bear class, or "blown" (blow up) when draw () in the following program fragment is called and Franny is passed in.
void Draw (const zooanimal &zoey) { zoey.draw ();} void foo () { ///Franny vptr points to the Zooanimal virtual table //rather than the Bear's virtual table Zooaniaml Franny = Yogi; Draw (yogi); Call Bear::d Raw () Draw (Franny); Call Zooanimal::d Raw ()}
Call virtual function Draw () via Franny,
the Zooanimal entity is used instead of the bear entity (although Franny is a Bear object yogi as the initial value). Because Franny is a Zooanimal object。 In factthe bear portion of the yogi has been cut during Franny initialization (sliced)。 If Franny is declared as a reference (or if it is a pointer and its value is Yogi's address), then draw () called by Franny will be the function entity of the bear.
The synthesized Zooanimal copy constructor explicitly sets the vptr of object to the virtual table of the Zooanimal class, rather than copying its vptr values directly from class object.
The existence of the virtual base class Subobject virtual base class requires special handling, if a class object takes another object as its initial value, and the latter has a virtual base class s Ubobject, it will also invalidate the "bitwise copy Semantics".
Each editor's support commitment to virtual inheritance means that the "virtual base class Subobject location in derived class object" must be prepared at the execution time. Maintaining the integrity of the location is the responsibility of the editor. "Bitwise copy Semantics" may break this location, so the editor must arbitrate in the copy constructor it has crafted itself. For example, in the following declaration, Zooanimal becomes a virtual base class for Raccon:
Class Raccon:public virtual Zooanimal {public: Raccon () {/* Set private Data Initial value * /} racccon (int val) {/* set privat e-Data Initial value */} //... private: //Required data};
The code generated by the compiler (to call Zooanimal's default constructor, initialize the vptr of Racccon, and locate Raccon zooanimal in subject) is inserted in two Raccon Between the constructors.
What about "memberwise initialization"? The existence of a virtual base class invalidates bitwise copy semantics. Second, the problem does not occur when "one class object takes another type of object as the initial value", but instead occurs in "a class object with an object of its derived classes as the initial value". For example, let Racccon Object takes a Redpanda object as the initial value, and Redpanda declares the following:
Class Redpanda:public Raccon {public: Redpanda () {/* Set private Data Initial value * /} redpanda (int val) {/* Set private data Initial value */}private: //...};
If you use an Reccon object as the initial value of another Raccon object, then "bitwise copy" is more than a poke.
Simple bitwise copy is enough to Raccon rocky; Raccon little_critter = Rocky;
However
If an attempt is made to use an Redpanda object as the initial value of the Little_critter, the compiler must determine whether "subsequent attempts by the programmer to access its zooanimal subobject are performed correctly"
Simple bitwise copy is not enough//compiler must explicitly initialize Litte_critter's virtual base class Pointer/offset Redpanda little_red; Raccon little_critter = little_red;
In this case,
to complete the correct Little_critter initial setting, the compiler must synthesize a copy constructor, inserting some code to set the initial value of the virtual base class Pointer/offset, Perform the necessary memberwise initialization operations on each of the members and perform other memory-related operations(3.4 For a more detailed discussion of virtual base classes)
In the following scenario, the compiler does not know if "bitwise copy semantics" is still maintained because it does not know whether the Raccon pointer points to a true Raccon object or to a derived class object:
Simple bitwise copy may suffice, may not be enough with Raccon *ptr; Raccon little_critter = *ptr;
When an initialization operation exists and maintains the state of "bitwise copy Semantics", if the compiler can guarantee that object has the correct and equal initialization, should it suppress the call of copy constructor so that its resulting program code is optimized?
At least under the synthetic copy constructor, the likelihood of program side effects is zero, so optimization seems reasonable. What if copy constructor is provided by the Class Designer? This is a controversial issue.
In the four cases described above, class no longer retains "bitwise copy semantics", and default copy constructor is considered nontrivial if not declared, in four cases If a declared copy constructor is absent, the compiler must synthesize a copy constructor in order to correctly handle "one class object as the initial value of another class object". The following section describes the policies that the compiler calls ocpy constructor and how these policies affect the program.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
C + + object model--copy Constructor construction Operations (chap. II)