Chapter13: Copy Control

Source: Internet
Author: User

Copy control operations: copy constructor, copy assignment operator, move constructor, move assignment operator, destructor.

The hardest part of implementing copy control Operations is to first recognize when these operations need to be defined .

    • copy Constructor :

If the first parameter of a constructor is a reference to its own class type, and any additional parameters have a default value, the constructor is copied when it is used.

Arguments are references: to avoid falling into recursion.

Copy constructors are implicitly used in several cases, so the copy constructor should not normally be explicit.

Synthetic copy constructors: Copy their data members one by another, copy the copy constructor for a member of the class type, copy the built-in type directly, and copy the members of an array type to the main element.

Direct initialization vs Copy initialization

When using direct initialization, we are actually asking the compiler to use normal function matching to select the constructor that best matches the parameters we provide;

When using copy initialization, we require the compiler to copy the right operand to the object being created , and convert the type if necessary;

Copy initialization is usually done by a copy constructor or a move constructor.

Copy initialization occurs :

1. Use = to define variables;

2. Pass an object as an argument to a non-reference type parameter;---> Copy the arguments to the constructor are references;

3. Returns an object from a function that returns a type other than a reference type;

4. Initialize an element in an array or a member of an aggregation class with a list of curly braces.

The compiler can bypass the copy constructor:

1 string " 9-999-99999-9 "; // Copy Initialization 2 // The compiler is allowed to put the following code 3 string null_book ("9-999-99999-9"); // the compiler skipped over the copy constructor

Copy assignment operator: Returns a reference to its left operand

Destructors

Destructors also have a function body and a destructor section. In a destructor, the function body is executed first, then the members are destroyed, and the members are destroyed in reverse order of initialization.

It is important to realize that the destructor body itself does not destroy members directly. A member is destroyed in the destructor phase that is suppressed after the destructor body.

Rule three/Five

Copy control should generally be considered as a whole.

A basic principle is to first determine whether this class requires a destructor. If this class requires a destructor, we can almost certainly need a copy constructor and a copy assignment function.

Block copy: Define a deleted function

Unlike =default, =delete must appear in the first declaration of a function, which is logically consistent with the meaning of these declarations. A default member affects only the code generated for this member, so =default is not required until the compiler generates the code. On the other hand, the compiler needs to know that a function is deleted in order to prohibit an attempt to use it.

We can specify =delete for any function.

If a destructor is defined as deleted, you cannot define a variable of that type.

synthetic Copy control functions may be deleted

If a class has data members that cannot be constructed, copied, copied, and destroyed by default, the corresponding member function is defined as deleted. The rules are extended as follows:

If a destructor for a member of a class is deleted or inaccessible, the class's composition destructor is defined as deleted, and the class's default constructor is deleted, and the composite copy constructor for the class is also defined as deleted. (if the destructor is defined as deleted, you cannot define a variable of that type.) )

If the copy constructor of a member of a class is either deleted or inaccessible, the composite copy constructor of the class is defined as deleted;

If the copy assignment operator of a member of a class is either deleted or inaccessible, or the class has a const or reference member , the synthetic copy assignment operator of the class is defined as deleted;

If a class has a reference member, it does not have an in-class initializer, or a class has a const member, there is no class initializer, and its type does not explicitly define a default constructor, the default constructor for that class is deleted.

PS: Explain why there are reference members, the synthetic copy assignment operator of a class is deleted? Because although you can give a new value to a reference, this changes the reference to the value of the object instead of the reference itself. If we have synthesized the synthetic copy assignment operator, after the assignment, the left operand still points to the same object as before the assignment, and the right operand does not point to the same object. Because this behavior is not what we expect, the synthetic copy assignment operator is defined as deleted.

Declaring but not defining a member function is legal ( with an exception to this ), attempting to access an undefined member will result in a link-time error.

    • Two methods of copy control and resource management: behavior-like value or behavior-like pointer

behavior Image Value :

Assignment operators typically combine the operations of destructors and constructors. Like destructors, assignment operations destroy the resources of the left-hand operand, and, like a copy constructor, the assignment operation copies data from the right operand. The point is that when an exception occurs, the left operand can be placed in a meaningful state.

The good pattern is that the right operand is copied to a local temporary object, and when the copy is complete, the existing members of the left-hand object are safely destroyed (the self-assignment is handled). Once the left object resource is destroyed, only the temporary object is copied to the left operand.

behaves like a pointer :

It is best to use shared_ptr to manage resources in the class.

Sometimes we want to manage resources directly, and then use reference counting.

    • Swap operation: Swap

If a class defines its own swap, the algorithm uses a class-custom version. Otherwise, the algorithm uses the swap defined by the standard library.

Since swap exists to optimize the code, we declare it as inline.

Unlike copy control members, swap is not necessary. However, defining swap may be an important optimization tool for classes that have resources assigned.

// the correct way to use swap using Std::swap;swap (r,h)

Classes that define swaps, typically using swap to define their assignment operators. These operators use a technique called copy and Exchange.

1 // Note that RHS is passed by value 2 hasptr& hasptr::operator=(hasptr rhs)3{4     Swap (* this, RHS); // swapping the contents of the left and local variables RHS 5     return *this; // RHS was destroyed . 6 }

This technique automatically handles self-assignment and is naturally exceptionally safe.

    • Right value and move

One of the most important features of the new standard is the ability to move rather than copy objects. In some cases, copies of objects are destroyed immediately after they have been copied. In these cases, moving, not copying, can significantly improve performance.

In the new container, we can use containers to hold non-copy objects as long as they can be moved.

We can see that the main move is to "run out of objects immediately destroyed", we need to identify these objects. To support the move operation, the new standard introduces an rvalue reference. The so-called rvalue reference is a reference that must be bound to an rvalue, and an important attribute of rvalue reference is that it can only be bound to an object that will be destroyed. Therefore, we are free to "move" the resource referenced by an rvalue to another object.

Rvalue references have binding properties that are reversed from Lvalue references: We can bind an rvalue reference to an expression that requires conversion, a literal constant, or an expression that returns an rvalue, but you cannot bind an rvalue reference directly to an lvalue.

Functions that return lvalue references, along with assignment, subscript, dereference, and forward increment/decrement operators, are examples of return lvalue expressions;

A function that returns a non-reference type, along with arithmetic, relationship, bit, and post increment/decrement operators, generates an rvalue. We can bind a const lvalue reference or an rvalue reference to such an expression.

So the difference between the left and right values is that the left value is persistent and the right value is ephemeral: either literal constants or temporary objects created during the evaluation of an expression.

Since the Rvalue reference can only be bound to a temporary object, we know that 1) the referenced object will be destroyed; 2) The object has no other user. These two features mean that code that uses rvalue references can freely take over the resources of the referenced object.

A variable is an lvalue: we cannot bind an rvalue reference to a variable of an lvalue reference type.

Many times, we need to bind an rvalue reference to an lvalue when we use it, and for that, the standard library provides a move that tells the compiler that we have an lvalue, but that we want to handle it like a right-hand value. This means commitment: we no longer use it except to assign or destroy this object. After calling Std::move, we cannot make any assumptions about the value of the source object after it is moved. That is, we can destroy a post-move source object, or we can give it a new value, but we cannot use the value of a post-move source object.

    • Move Constructors & Move Assignment functions

With moving objects, how do you move them?

In addition to completing the move of a resource, the move constructor must also ensure that the source object is in such a state after it has been moved-destroying it is harmless. In particular, once a resource completes the move, the source object must no longer point to the resource being moved-ownership of those resources has been attributed to the newly created object.

Moving, standard library containers, and exceptions

because the move operation "steals" resources, it typically does not allocate resources . Therefore, the move operation does not throw any exceptions. We should inform the standard library, otherwise we will do some extra work to deal with this possibility.

Therefore: The move constructor and move assignment operators that do not throw exceptions must be marked as noexcept.

Why is it? (about the standard library's interaction with our custom classes)

Although a move operation usually does not throw an exception, it is allowed to throw an exception, and second, the standard library container can protect its own behavior when an exception occurs.

For example, the vector guarantees that when the vector calls Push_back, the vector itself does not change when an exception occurs. How do you do that?

When push_back requires that space be redistributed, the old space is moved to new memory. Moving an object usually changes its value. If the reassignment process uses a move constructor and throws an exception after moving some, but not all, of the elements, the post-move source element in the old space has changed and the new space is not yet present.

To address this potential problem, unless the vector knows that the move constructor of the element type does not throw an exception, it must use the copy constructor instead of the move constructor in the process of reallocating memory.

Synthetic move operations

If we do not declare our own copy constructors or copy assignment functions, the compiler will always synthesize these operations for us.

Unlike copy operations, the compiler does not synthesize a move operation for some classes at all. In particular, if a class defines its own copy constructor, copy assignment operator, or destructor, the compiler does not synthesize the move constructor and the move assignment operator for it.

The compiler will synthesize a move operation for a class only if it does not define any copy control members of its own version, and every non-static data member of the class can be moved.

The move operation of the composition is the case of deletion :

When a class member does not define a move operation or the compiler cannot compose a move operation for it, the synthetic move operation is deleted;

A move operation with a class member is either deleted or inaccessible; (a move operation can never be implicitly defined as a deleted function, but if the display is defined as default but cannot move all members, the function defined as deleted)

The destructor of the class is either deleted or inaccessible;

If a class member is a const or a reference, the move assignment operator is deleted;

In the case of both a move constructor and a copy constructor:

1 Foo (const foo&); 2 Foo (foo&&);

Use the move constructor when passing the right value, and use the copy constructor when passing the left value;

However, if there is no move constructor, the right value can also be bound to the Const lvalue reference, at which point the copy constructor is called.

Do not use the move operation arbitrarily

By using move carefully with the class code, you can significantly improve performance. If you arbitrarily use the move operation in normal user code, it is likely to lead to inexplicable, difficult to find errors, it is difficult to improve the performance of the application.

    • member functions and Rvalue references

Sometimes, if a member function provides both copy and mobile versions, it can also benefit from it. This member function typically uses the same parameter pattern as copy/move: A version accepts a const lvalue reference, and a version accepts a non-const rvalue reference.

We do not need to define a version that accepts a const x&& or x& parameter, and when we steal the data, it is necessary to change the source, and when it is copied, it must not change the object.

1 void X::p ush_back (conststring& s)2{3     alloc.construct ( first_free++, s); 4 }5void X::p ush_back (string&& s)6{  7     alloc.construct (first_free++, Std::move (s)); 8 }

Typically, we call member functions on an object, regardless of whether the object is an lvalue or an rvalue, so it cannot be prevented:

s1+s2="wow! ";

Now, however, we can force the left operand to be an lvalue, just like Const. That is, place a reference qualifier after the argument list.

When const and reference qualification are used together, the reference qualifier is placed after the const.

When we define a const member function, we can define two versions, the difference is only the const, and the reference qualification is different, you must either add a reference qualifier or none.

Chapter13: Copy Control

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.