In C + +, there are three major functions of copy control (copy constructor, assignment operator, destructor), and in C++11, move constructor is added to move assignment operator. I would venture to name them six functions.
First, the constructor function
C++primer said: Constructors are special member functions, and constructors are executed whenever a new object of the class type is created. The job of the constructor is to ensure that the data members of each object have appropriate initial values.
Constructors differ from other functions: constructors and classes have the same name, and no return type.
Constructors are the same as other functions: constructors also have tangible parameter tables (which can be void) and function bodies. (The constructor for the parameter table void is the default constructor)
The order in which the constructor constructs the class object is:1. Memory allocation, when the constructor calls the hermit \ Displays the initialization data.
2. Perform the operation of the constructor.
1. Constructor initialization table
A (): a (0) {}
We use constructor initialization to represent the initialization of a data member, whereas a constructor that does not use an initialization table assigns a value to the data member in the constructor body.
When we write a class, some members must initialize in the constructor initialization table. (class type member without default constructor, const or reference type member)
When writing code, it is important to note that you can initialize const objects or objects of reference types, but they cannot be assigned values. That is, we need to do the initialization work before we execute the constructor function body, so the only chance is to initialize the table. From this you can see that the execution of the initialization table precedes the body of the function.
In the initialization table, the order in which members are initialized is not the order in which you write the initialization table, but the order in which members are defined.
Initializing a list when initializing a member of a class type, you specify the argument and pass it to a constructor of the member type.
There is an example of a bookstore in C++primer:
Sales-item (): ISBN (10,' 9 '), Units_sold (0), Revenue (0.0) {}
When does our initialization table have to be used?
When there is a class member, which is itself a struct or a class, and there is only one constructor with parameters, (no default constructor) at this point we want to initialize the member, we need to invoke the constructor of the member, we need to initialize the table, if the initialization table is not used, then memory allocation will be problematic.
Advantages of initializing lists: primarily for custom types, the initialization list is a function of the body before he invokes the constructor to initialize the object.
In the body of a function, however, you need to call the constructor and then assign the value so that it is less efficient than initializing the table.
2. Default argument constructors
A (int i = 1): A (i), CA (i), RA (i) {}
3. Default constructor
default constructor for composition: The compiler automatically generates a function when a constructor is not defined in the class (note that it is a constructor).
But we can't rely too much on compilers, and if we have compound types or custom type members in our class, we need to define our own constructors.
Custom Default constructors:
A (): a (0) {}
A (int i = 1): A (i) {}
It may be doubtful that the second constructor is also a default constructor? Yes, because the parameters have default values.
Let's look at a picture and we'll see it at a glance:
Explicit Sales_item (const string &book): ISBN (book) {}
If we declare that the constructor prohibits implicit conversions, you can pass other objects to the constructor after conversion.
String a = "D";
Item.same (Sales_item (a));
Second, move the constructor function
New features added in C++11!
In the previous blog I added a graph, you can see the movement of the structure of the operation of the principle of the function.
At this point, we stole the memory space of the temporary variable, which was used for our own use. Save time to open up space.
A (a && h): A (H.A)
{
H.A = nullptr; You remember nullptr?
}
As you can see, the parameters of this constructor are different, there are two & operators, and the move constructor receives the "rvalue reference" parameter.
Also, let's say, here h.a is empty, and if you don't do this, h.a the execution of the destructor at the end of the move constructor will deconstruct the memory we stole. H.A will become a dangling pointer.
When does the move constructor fire? That's the temporary object (the right value). The move semantics are executed when the temporary object is used.
It should be noted here that the exception occurs, to try to ensure that the movement of the constructor does not occur, you can pass the Noexcept keyword, here you can ensure that the move constructor thrown out of the exception will be directly called terminate termination program.
Rvalue references:
In the previous blog, we mentioned the death value, which is a new expression related to Rvalue reference in c++11.
In C++11, an rvalue reference is a type that references a right value, and the right value usually does not have a name, and we can only find it by reference.
Compare the following two statements:
T &&a = Returna ();
T B = Returnb ();
At this point A is an rvalue reference, and he has less than b the process of object destruction and object construction. A directly binds the temporary variable returned by Returna. B is only constructed from a temporary variable value.
Should be able to see clearly. An rvalue reference is the return of the right value (the temporary object) to be reborn, extending the life cycle. The temporary object is destructor, but the rvalue reference is alive.
Note, however, that rvalue references cannot be bound to an lvalue: int A; int &&c = A; This is not going to work.
Here is a function called the move function, which can cast an lvalue to an rvalue reference.
Third, move assignment operator
His principle is the same as the move constructor, which is no longer mentioned here.
Give the implementation code:
A & operator = (a&& h)
{
ASSERT (This! = &h);
A = nullptr;
A = Move (H.A);
H.A = nullptr;
return *this;
}
Replication control
Iv. Copy Constructors
He is a special constructor with a single formal parameter, which is a reference to that class type. When you define a new object and initialize it with an object of the same type, the copy constructor is used explicitly. When you pass an object of that type to a function or return an object of that type from a function, the copy constructor is used implicitly.
You must define the condition of the copy constructor:
1. A class has one or more data members that are pointers.
2. There are members that represent other resources allocated in the constructor. Another class must do some specific work when creating a new object.
Here's how to write the assignment constructor:
A (const a& h): A (H.A) {}
What if you don't want to copy the object? Then declare the copy constructor as: private;
Five, assignment operators
As with constructors, assignment operators can be overloaded by making different types of right-hand operands.
Assignment and replication are often used together, and this should be noted.
Here is the notation for the assignment operator:
a& operator = (const a& h)
{
ASSERT (This! = &h);
This->a = H.A;
return *this;
}
Vi. Destructors
is a complement to the constructor, and the destructor is automatically applied when the object goes out of scope or dynamically allocated objects are deleted. Destructors can be used to dispose of resources when objects are constructed or acquired during the life of an object. The compiler automatically executes destructors for non-static data members of the class, regardless of whether the class defines its own destructor.
To run the destructor:
Destructors are not executed when an object reference or pointer is out of bounds, and the destructor is called only if a pointer to a dynamically allocated object is deleted or the actual object goes out of scope.
Composition destructor:
The compiler always synthesizes a destructor, and the composition destructor revokes each non-static member in reverse order when the object was created. Note that the composition destructor does not remove the object that the pointer member points to.
Finally, it is important to note that if a destructor is required for a class, then he must also copy the constructor and assignment operators.
The end of the blog gives the complete six functions of the code
#include <iostream>
#include <assert.h>
using namespace Std;
Class Temp
{
Public
Temp (const char* str = nullptr);
Temp (temp&& t);
temp& operator = (temp&& t);
Temp (const temp& t);
temp& operator = (temp& t);
~temp (void);
Private
Char *m_pdata;
};
Temp::temp (const char* STR)
{
if (!STR)
{
M_pdata = nullptr;
}
Else
{
This->m_pdata = new Char[strlen (str) + 1];
strcpy (This->m_pdata, str);
}
}
Temp::temp (temp&& t): M_pdata (Move (T.m_pdata))
{
T.m_pdata = nullptr;
}
temp& Temp::operator = (temp&& t)
{
ASSERT (This! = &t);
This->m_pdata = nullptr;
This->m_pdata = Move (T.m_pdata);
T.m_pdata = nullptr;
return *this;
}
Temp::temp (const temp& t)
{
if (!t.m_pdata)
{
This->m_pdata = nullptr;
}
Else
{
This->m_pdata = new Char[strlen (t.m_pdata) + 1];
strcpy (This->m_pdata, t.m_pdata);
}
}
temp& temp::operator = (Temp &t)
{
if (This! = &t)
{
Delete[] this->m_pdata;
if (!t.m_pdata)
{
This->m_pdata = nullptr;
}
Else
{
This->m_pdata = new Char[strlen (t.m_pdata) + 1];
strcpy (This->m_pdata, t.m_pdata);
}
}
return *this;
}
Temp::~temp (void)
{
if (This->m_pdata)
{
Delete[] this->m_pdata;
This->m_pdata = nullptr;
}
}
C++11 six functions (constructor, move constructor, move assignment operator, copy constructor, assignment operator, destructor)