C ++ copy constructor, copy assignment operator, mobile constructor, mobile assignment operator, destructor, right value reference, reference qualifier instance, right value of Constructor
13.1 copy, assign value, and destroy 13.1.1 copy constructor
The first parameter of the copy constructor must be a reference type, usually a reference of const. When passing function parameters, parameters of the non-reference type need to be copied and initialized. If the parameters of the copy constructor are of the non-reference type, they will be in an endless loop. All parameters except the first parameter must have default real parameters. If no copy constructor is defined, the compiler automatically merges one. Composite copy constructor: copies each non-static member to the current object once from a given object. Copy initialization:
When the object is initialized with =. Non-reference parameter transfer. The return value of a non-referenced function. List initialization array elements or aggregate class members.
Struct A {int n, I; A (int n = 1): n (n) {} A (const A & a, int I = 3): n (. n), I (I) {}// the first parameter must be referenced, and other parameters must have default real parameters (for implicit conversion)}; void main () {A a (2); // directly initialize A B (a); // copy initialization // A B = a; // cout <B. n <"" <B. I <endl; // output 2 3}
13.1.2 copy assignment operator
If the operator is a member function, the operation object on the left is bound to the implicit this parameter. The value assignment operator usually returns a reference to the operation object on its left. If you do not define your own copy assignment operator, the compiler will generateMerge copy assignment operator.
13.1.3 destructor
Used to release resources used by objects and destroy non-static data members of objects. Implicitly destroys a member of the built-in pointer type and does not delete the object to which the Member points. Smart pointer members are automatically destroyed in the Destructor stage. Time when the Destructor is called (the object is destroyed ):
The variable leaves the scope. The object is destroyed, and the members are also destroyed. The container is destroyed, and the elements are also destroyed. Dynamically assigned object. When delete is applied to the pointer to it. When the complete expression is created, the temporary object ends. When a pointer to an object is referenced or out of scope, the Destructor will not be executed.
13.1.4 Rules 3/5
If a class requires destructor, you must copy the constructor and copy the value assignment operator (for example, if the Destructor wants to destroy the pointer, each object pointer belongs to itself, the pointer cannot be copied directly. A new pointer is required ). If a class requires a copy operator, you must also copy the constructor, and vice versa. But not necessarily require destructor (for example, different sequence numbers of each object must be indicated during copy, and re-copy is required, but it is not related to the analysis structure ).
13.1.5 use = default
Similar to constructor, = default requires the compiler to generate the copy control Member of the merged version. The default value is implicit inline. Non-class definitions of members are not inline.
13.1.5 block copying
DefinitionDeleted FunctionTo block copying. Add = delete to the function parameter list. Unlike = default, = delete must appear when the function is declared for the first time. You can specify = delete for any function. If a deleted destructor is specified, objects of this type cannot be destroyed, and their variables and pointers to dynamically allocated objects cannot be released. When it is impossible to copy, assign values, or destroy a class member, the merging and copying control members of the class are defined as deleted. It is not recommended that you declare the private copy constructor and the copy assignment operator.
13.2 copy control and Resource Management 13.2.1 for pointer members, the class of behavior Image value should create a new pointer instead of directly copying it. Otherwise, the value to be directed is the same. If an object is assigned to itself, the value assignment operation must be correct. Most assignment operations combine the work of destructor and copy constructor.
Struct Value {int * p; Value (int n = 0): p (new int (n) {} Value (const Value & value ): p (new int (* value. p) {} // copy constructor of the Value type: the pointer must re-create Value & operator = (const Value &);~ Value () {delete p ;}}; Value & Value: operator = (const Value & rv) {// copy the Value first and then clear the original Value, avoid processing the object itself. If the object is cleared and then copied, an error occurs when auto newp = new int (* rv. p); // first copy the value of the passed pointer. the pointer must be re-created to delete p; // then delete the original value. P = newp; // return * this;} void main () {Value v1 (3); // constructor Value v2 (v1 ); // copy the constructor Value v3; v3 = v1; // copy the value assignment operator cout <* v1.p <"" <* v2.p <"" <* v3.p <endl; // output 3 3 v1 = v1; // assign the value of v1 to itself, correct * v2.p = 123; // modify the pointer value pointed to by v2 and v3 * v3.p = 666; cout <* v1.p <"" <* v2.p <"" <* v3.p <endl; // output 3 123 666}
13.2.2 the class defining the behavior like pointer imitates shared_ptr and designs its own reference count. The counter is a pointer and is dynamically allocated for sharing.
When you create an object (constructor), the counter is initialized to 1. Copy the constructor, share the counter, and add the counter. Destructor. The counter is reduced. If it is 0, the object is released. Copy the value assignment operator to add counters (similar to the copy constructor) for the right object and reduce the counters (similar to the destructor) on the left ).
Class Pointer {public: int * p; Pointer (int n = 0): p (new int (n), count (new std: size_t (1 )) {} // constructor. The initialization counter is 1 Pointer (const Pointer & ptr): p (ptr. p), count (ptr. count) {++ * count;} // copy the constructor. the Pointer is copied directly. The counter is shared and incremented by Pointer & operator = (const Pointer &);~ Pointer (); private: std: size_t * count;}; Pointer ::~ Pointer () {if (-- * count = 0) // when the last object of the Destructor {delete p; // destroy the shared data delete count; // destroy counter} Pointer & Pointer: operator = (const Pointer & rp) {++ * rp. count; // increase the right value first, and then decrease the left value. Avoid errors when assigning values. If (-- * count = 0) // decline the same as the Destructor {delete p; delete count;} p = rp. p; // Finally, copy the pointer and counter (both pointing to the same value) count = rp. count; return * this;} void main () {Pointer p1 (8); // constructor Pointer p2 (p1); // copy constructor Pointer p3; p3 = p1; // copy the value assignment operator cout <* p1.p <"" <* p2.p <"" <* p3.p <endl; // output 8 8 8 * p2.p = 2; // modify any object (p1 p2 p3 ), shared data member p cout <* p1.p <"" <* p2.p <"" <* p3.p <endl; // output 2 2 2}
13.3 switch operation
A copy and two assignments are usually required for one exchange.
Struct Value {... // Value & operator = (const Value &); Value & operator = (Value); // copy and exchange, another method for copying Value assignment: friend void swap (Value &, value &); // exchange element, marking friends to access private members} inline void swap (Value & lv, Value & rv) {swap (lv. p, rv. p); // directly exchange the pointer} // The parameter is passed by Value, so the copy constructor is called to create rvValue & Value: operator = (Value rv) {swap (* this, rv); // return * this for the left-side operation object and rv; // After the function is completed, the rv is destroyed (that is, the original value ).}
13.5 dynamic memory management
Moving Elements instead of copying elements during memory reallocation
Create a new memory to construct a part of the object first, move the original elements directly to destroy the elements in the original memory, and release the space.
13.6 move objects
The standard library container, string, and shared_ptr support both moving and copying. IO and unique_ptr classes can be moved but cannot be copied.
13.6.1 right value reference
A regular reference is called a left value reference. The value that the right reference and the left reference can bind is complementary. Only one object to be destroyed can be bound. It can take over the resources of the referenced object and "steal" The State of the object.
Int I = 123; int & r = I; // The correct int & rr1 = 123; // The correct int & rr2 = I; // error, the right value reference cannot be bound to the int & r2 = I * 2; // error. The left value reference cannot be bound to the right value const int & r3 = I * 2; // correct, you can bind the right value int & rr3 = I * 2; // if it is normal, bind it to the multiplication result.
13.6.2 mobile constructor and mobile assignment operator
The first entry is a reference of the right value, and additional parameters must have default arguments. After the resource is moved, the source object must no longer point to the moved Resource (nullptr is set as the pointer) because the ownership of these resources has been assigned to the new object. Moving usually does not allocate resources, so no exception is thrown. Mark notest. The standard library container can guarantee its own behavior when an exception occurs. If nostmte is marked, the mobile constructor is used; otherwise, the copy constructor is used.
When an exception occurs during memory reallocation:
The mobile constructor has modified the old container, and the new container element does not exist. The old container that copies the constructor has not changed, and the newly assigned container can be released directly. Unlike the copy operation, the compiler does not merge and move some classes.
If you define your own copy constructor, copy assignment, or destructor, the mobile constructor and the mobile assignment operator are not merged. Only when the class does not define any version of the copy control member, and each non-static data member can be moved, the compiler will synthesize the mobile constructor and the moving value assignment operator. Unlike the copy operation, a mobile operation is never implicitly defined as a delete operation. Explicitly requires that a move operation = default be generated, and the compiler cannot move all members, the compiler will define the move operation as Delete. If a class defines a mobile constructor or a mobile assignment operator, the synthesis and copy constructor and copy assignment are defined as deleted. It is generally safe to replace the mobile constructor with a copy constructor.
Struct Value {Value (Value & v) notest: p (v. p) {v. p = nullptr;} // move the constructor. After moving the constructor, set the source to null Value & operator = (Value );}; // both the Moving Value assignment operator (when the parameter is the right Value) and the copying Value assignment operator (when the parameter is the left Value) Value & Value: operator = (Value rv) {swap (* this, rv); return * this;} void main () {Value v1 (111); Value v2 (std: move (v1 )); // move constructor cout <* v2.p <endl; // After moving, the ownership of v1 is handed over to v2. If v1 is called, an exception Value v3 is generated; v3 = v2; // v2 is used as the left value, and a copy is called. There is still a valid cout in v2 <* v3.p <endl; v3 = std: move (v2 ); // use std: move to bind the right value and call the move operation. v2 expires cout <* v3.p <endl ;}
Mobile iterator: The dereference operator generates a reference to the right value. Use the make_move_iterator function of the standard library to convert a normal iterator into a mobile iterator.
// Copy the elements between begin () and end () to: first as the initial uninitialized memory. Uninitialized_copy (begin (), end (), first); // The original iterator cannot be used. Uninitialized_copy (make_move_iterator (begin (), make_move_iterator (end (), first );
13.6.3 right-value reference and member functions can provide member functions with moving and copying versions.
// Push_back in the standard container provides two versions: void push_back (const T &); // copy: bind any type of Tvoid push_back (T &); // move: only bind the right value that can be modified to int I = 5; vector
Vi; vi. push_back (I); // call push_back (const int &) vi. push_back (2); // call push_back (int &&)
Reference qualifier ):
&: Only the left value can be operated. &: Indicates that only the right value can be operated.
// In the old standard, if there is a right value reference operation, the following problems will occur: string s1 = "aaa", s2 = "bbb"; s1 + s2 = ""; // correct, but meaningless. // Solve the problem by using the reference qualifier: class A {public: A sorted () &; // After the parameter list, add &, the object is the right value, you can directly modify the content in the original address. A sorted () const &; // Add & after the const. if the object is A const or left value, you cannot directly operate on the original address .}
During overload: if two or more member functions with the same name and the same parameter list are defined, the reference qualifier must be added to all functions, or none.