Those things in C + +: Copy control of Classes

Source: Internet
Author: User

1. What is the copy control of a class

When we define a class. To make our defined class types as useful as built-in types (char,int,double, etc.), we usually need to test the following:

Q1: There is an object of the same type that initializes the object with this class.

Q2: Assigns an object of this class to an object of the same type.

Q3: Let the object of this class have a life cycle. For example, a local object needs to be destroyed when the code department ends.

copy constructor (copy constructor)

move constructor (move constructor)

copy assignment operator (copy-assignment operator)

Move assignment operator (move-assignment operator)

destructor (destructor)

The first two constructors occur at Q1. The middle two assignment operators occur at Q2, and the destructor is responsible for destroying the class object.

But for those who have just begun to learn, it is both a boon and a disaster to assume that we do not define these control operators in defined classes, and the compiler will take the initiative to synthesize a version number for us. This sometimes seems like a good thing. But the compiler is not omnipotent, its behavior in very many times is not what we want.

So, the hardest part of implementing copy control is recognizing when you need to define these operations .

2. Copy constructor

A copy constructor is one of the constructors, whose parameters are references to its own class type, and assume that there are other parameters. Any additional parameters will have a default value.

Class foo{Public:     Foo ();     Foo (const foo&); };

We can notice a few problems from the above code:

1, we define the shape as a const type, although we can also define non-const formal participation. But this is basically meaningless. Because the function's function only involves the member's copy operation.

2, the shape is a reference to the class type itself, and must be a reference type. Why is it?

We know that the value passed between the function's actual participation and the formal participation is through the copy.

So when we pass the object of that class to the formal participation of a function. The copy constructor of the class is called. The copy constructor itself is also a function. Because it is a value pass instead of a reference, it is called to call the copy constructor of the class (itself) so that the infinite loop goes on and cannot be completed.

3, the copy constructor is passed by not explict.

Suppose we don't define a copy constructor, the compiler defines one for us. This function copies each non-static member in turn from the given object to the object being created. The type of the member itself determines how it is copied: a member of the class type is copied using its copy constructor, the built-in type is copied directly, and the array members are copied element-wise .

Differentiate between direct initialization and copy initialization:

String name ("Name_str");        Direct initialization of String name = String ("Name_str");    Copy initialization of String name = "Name_str";        Copy initialization

Direct initialization is a requirement that the compiler use normal function matching to select the constructor that best matches the number of references we provide. When we use copy initialization, we ask the compiler to copy the right side operand to the object being created. If necessary, type conversion is also required (the third line of code hides a C-style string converted to a string type).

3, Copy assignment operator

The copy assignment operator is an overloaded function on an assignment operator that returns a reference to the left-hand operand.

Class Foo {public:     foo& operator= (const foo&);};

As with copy constructors, it is assumed that a copy assignment operator is not defined for a class. The compiler will synthesize one for it.

4, destructor

Destructors consist of a wavy line-up class name, which does not return a value and does not accept a number of parameters.

Because there are no parameters, there is no overloaded function. This means that a class has only one destructor.

Destructors do things in contrast to constructors, so let's look back at what a constructor does:

1, each member is created in the order defined by the member.

2. Initializes each member according to the member initialization list.

3. Run the constructor function body.

In the destructor, there is no such thing as the initialization list in the constructor to control how members are destroyed, and the part of the destructor is implicit.

How a member destroys a type that depends on the member itself. The assumption is that the class type calls its own destructor, assuming that the built-in type will voluntarily destroy itself.

Instead of assuming a pointer, you need to manually release the space that the pointer points to. Unlike a normal pointer, a smart pointer is a class. It has its own destructor.

So when will the destructor be called? When the object is destroyed:

  • The variable is destroyed when it leaves its scope;
  • When an object is destroyed, its members are destroyed.
  • When the container is destroyed. Members are destroyed.
  • For dynamically allocated objects, the delete operator is destroyed when the pointer to it is applied.

  • For temporary objects. is destroyed when the event expression that created it ends.

The notable destructors are self-executing. The function body of the destructor does not destroy the member directly, and the member is destroyed in the destructor phase that is suppressed after the destructor body.

During the entire object destruction process. The destructor body is performed as part of the member destruction step.

5, define the principle of copy control operation

As mentioned in the 1th, the most difficult thing to do with copy control when defining a class is when you need to customize it. When do you want the compiler to synthesize itself.

Then we can have the following 2 principles:

Assuming a class needs to define a constructor, it is almost certain that it also requires a copy constructor and a copy assignment function. In turn, not necessarily . .

Suppose a class requires a copy constructor. It is almost certain that it also requires a copy assignment function, and vice versa.

Why is the destructor so closely related to the copy constructor and the assignment function? Or why should we put destructors together when we talk about copy control (5 kinds)?

First of all. We think about when we have to define destructors ourselves. For example, there is a dynamic allocation of memory within a class.

Class Hasptr {public:     hasptr (const STRING&S = string ()):p s (new string (s), I (0)) {}     ~hasptr () {delete ps;} PR Ivate:     int i;     string* PS; };

We know that the assumption is that the compiler itself is the destructor of the active composition, it will not delete the pointer variable, so PS point to the memory will not be freed, so an active definition of the destructor is required. Then assume that the copy constructor and copy assignment function are not defined for this class. What's going to happen?

The version number of the compiler's own active composition. A simple copy of the pointer member, which means that multiple Hasptr objects may point to the same memory.

Hasptr p ("some values"); f (p);        When F ends, the memory that p.ps points to is released Hasptr Q (P);//now P and Q all point to invalid memory

6, using =default and =delete

We can use =default to explicitly ask the compiler to generate a composite version number. The synthesized function is implicitly declared as inline. Assuming that we do not want the members of the composition to be inline, =default should be used only for out-of-class definitions of members.

Sometimes we define classes that do not require copy constructors and copy assignment operators, such as the Iostream class to block copies to prevent multiple objects from writing or reading the same IO buffer.

In the new standard. We are able to add =delete to the list of copy constructors and copy assignment operator functions to indicate that we want to define it as deleted, a function called a delete function.

Class NoCopy {     NoCopy () = default;    Use the composition's default constructor     NoCopy (const nocopy&) = delete;        Delete Copy     nocopy& operator= (const nocopy&) = delete;    Delete Assignment     ~nocopy () = default;    Use the destructor of the composition};

Note: Destructors cannot be members of a delete because this class cannot be destroyed.

Suppose a class has a const member or a reference member . This type of synthetic copy assignment operator is defined as deleted.

Before the new standard comes out, the class is prevented from copying by declaring the copy assignment operator of its copy constructor as private, and in order to prevent members from being interviewed by friends or other members. These member functions are declared only, but not defined.

7. Rvalue reference

A so-called rvalue reference is a reference that must be bound to the right value. We are able to get rvalue references through &&, and rvalue references a very important property is to bind only to an object that will be destroyed, so we are free to "move" the resource referenced by an rvalue to an object.

We are able to bind an rvalue reference to an expression. However, you cannot bind an rvalue reference to a left-hand value:

int i = 42; int &r = i;        Correct: R references I int &&rr = i;    Error: Cannot bind an rvalue reference to an lvalue on int &r2 = i *;    I*42 is a right-valued const int& R3 = i *;    The ability to bind a const reference to a right value on int && RR2 = i *;    Correct: Bind the RR2 to the multiplication result

Overall: The left value has a persistent state, and the right value is either a literal constant or a temporary object created during the evaluation of an expression.

So we know that the reference to the Rvalue reference: 1 will be destroyed; 2) The object has no other user.

The standard library provides a std::move function that allows us to get an rvalue reference on an lvalue:

int  &&r3 = Std::move (RR1);//RR1 is a variable

The move call tells the compiler that we have a left-hand value. But we want to treat it like a right value one. After the above code, either destroy the RR1 or assign a value to the RR1, otherwise we will not be able to use RR1.

Another notable point is that we use std::move instead of move. Even if we provide a using declaration.

8, move constructor and move assignment operator

Like a copy, a move operation occurs when an object of one of our classes is initialized or assigned to an object of the same class type. But unlike the copy, it is. The contents of the object are actually moved from the source object to the target object, and the source object loses the content.

The move operation typically occurs only when the source object is a Uname object.

A Uname object means a temporary target that has not been given a name, such as a function return value that returns the type, or an object returned by a type conversion operation.

MYCLASS fn ();            Function returning a MyClass objectmyclass foo;             Default Constructormyclass bar = foo;       Copy Constructormyclass baz = fn ();      Move Constructorfoo = bar;               Copy Assignmentbaz = MyClass ();         

The objects returned by FN () and the objects constructed by MyClass are unnamed in the code above, and are not required to be copied when assigned to MyClass or initialized with this object. Because the source object has only a very short life cycle.

The definition of a moving constructor and a moving assignment function is the same as the copy operation, which simply converts the reference of the copy function to an rvalue reference.

MyClass (myclass&&);             move-constructormyclass& operator= (myclass&&);  Move-assignment

Mobile operations are useful for classes that need to manage storage space, such as the one we define below:

Move Constructor/assignment#include <iostream> #include <string>using namespace Std;class Example6 {    string* ptr;  Public:    Example6 (const string& str): PTR (new string (str)) {}    ~example6 () {delete ptr;}    Move constructor    Example6 (example6&& x): ptr (x.ptr) {x.ptr=nullptr;}    Move Assignment    example6& operator= (example6&& x) {      delete ptr;       ptr = x.ptr;      X.ptr=nullptr;      return *this;    }    Access content:    const string& Content () const {return *ptr;}    Addition:    Example6 operator+ (const example6& RHS) {      return Example6 (content () +rhs.content ());}    }; int main () {  Example6 foo ("Exam");  Example6 bar = Example6 ("ple");   move-construction    foo = foo + bar;                  Move-assignment  cout << "foo ' s content:" << foo.content () << ' \ n ';  return 0;}


things about C + +: Copy control of classes

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.