Learning this chapter first requires a certain understanding of the dynamic memory allocation.
There are six special member functions for the class, as follows:
Let's now analyze each of these:
1 default constructor
The default constructor believes that everyone is unfamiliar, calling the default constructor only if no constructor is declared or if the object does not have any initialization parameters at the time of declaration.
Class Example {public
:
int total;
void accumulate (int x) {total = x;}
};
The compiler assumes that example has a default constructor. Therefore, the object of the class can be simply declared without using any parameters.
Example ex;
However, as long as the constructor of a class is explicitly declared with any argument, the compiler does not implicitly invoke the default constructor, which means that the declaration of the class object is no longer allowed to use parameters. For example, the following class:
Class Example2 {public
:
int total;
Example2 (int value): Total (value) {};
void accumulate (int x) {total = x;};
Here, we declare a constructor with an int. Therefore, the following object declaration is correct:
Example2 EX (100);
However, the following statement is not correct:
Therefore, a class can replace the default constructor with an explicit constructor with one parameter. Therefore, if a class object needs to use an parameterless declaration, the class must have the correct default constructor. For example:
Class and default constructors
#include <iostream>
#include <string>
using namespace std;
Class Example3 {
string data;
Public:
Example3 (const string& str): Data (str) {}
Example3 () {}
const string& content () const {Retu RN data;}
;
int main () {
Example3 foo;
Example3 Bar ("Example");
cout << "Bar" content: "<< bar.content () << ' \ n ';
return 0;
}
Here, Example3 has a default constructor, which has an empty function body.
Example3 () {}
The above Example3 is the default constructor, which is called when there are no other constructors in the class declaration. However, there are other constructors in the example above:
Example3 (const string& str);
If any of the constructors are explicitly declared in the class, the default constructor is not automatically provided.
2 destructor
What is a destructor.
Destructors typically appear in pairs with constructors, and are primarily used by class objects to free up the memory of an object at the end of the declaration cycle. To do this, the destructor appears old.
Look at the following example:
Destructors
#include <iostream>
#include <string>
using namespace std;
Class Example4 {
string* ptr;
Public:
//constructors:
Example4 (): PTR (new string) {}
Example4 (const string& str): PTR (new string (St R)) {}
//destructor:
~example4 () {delete ptr;}
Access content:
const string& Content () const {return *ptr;}
};
int main () {
Example4 foo;
Example4 Bar ("Example");
cout << "Bar" content: "<< bar.content () << ' \ n ';
return 0;
}
In Example 4, the storage space is allocated for a string, and the storage space is released later by the destructor.
3 Copy Constructors
The copy constructor is invoked automatically when a newly constructed object is initialized with an initialized custom class type object to initialize. That is, the copy constructor will be invoked when the object of the class needs to be copied. Copy constructors are called in the following situations:
(1) An object is passed into a function body in the form of a value
(2) The return of an object from a function in a way that is passed by value
(3) An object needs to be initialized by another object.
If you do not explicitly declare a copy constructor in a class, the compiler will automatically generate a default copy constructor that completes a bit copy between objects. A bit copy is also known as a shallow copy, which is described later.
A custom copy constructor is a good programming style that prevents the compiler from forming a default copy constructor that increases the efficiency of the source code.
Shallow copy and deep copy
In some cases, a member variable in a class needs to dynamically open up heap memory, and if a bit copy is implemented, the value in the object is completely copied to another object, such as A=b. At this point, if a member variable pointer in B has already applied for memory, that member variable in a also points to the same memory. This is the problem: when B releases the memory (e.g., destructor), the pointer in A is a wild pointer, and a run-time error occurs.
Deep copy and shallow copy can be easily understood as: If a class has resources, when the object of this class occurs when the replication process, the resource reallocation, the process is a deep copy, conversely, no reallocation of resources, is a shallow copy. Here's an example of a deep copy.
Copy constructors: Deep copy
#include <iostream>
#include <string>
using namespace std;
Class Example5 {
string* ptr;
Public:
Example5 (const string& str):p TR (new String (str)) {}
~example5 () {delete ptr;}
Copy constructor:
Example5 (const example5& x):p tr (New String (X.content ()) {}
//access String for class:
const string & Content () const {return *ptr}
};
int main () {
Example5 foo ("Example");
Example5 bar = foo;
cout << "Bar" content: "<< bar.content () << ' \ n ';
return 0;
}
In the code above, in the list of parameters for the copy constructor, the new string storage location is used to store the string contents of the old class object that was copied over. With such an action, two objects have the same content, but they store a different string of locations.
To summarize the basic concepts and knowledge you need to know about deep copies and shallow copies:
(1) When to use the copy function.
A. An object passes through the function body in a way that is passed by value;
B. An object is returned from a function in a way that is passed by value;
C. An object needs to be initialized with another object.
If you do not explicitly declare a copy constructor in a class, the compiler will automatically generate a default copy constructor that completes a bit copy between objects. Bit copies are also called shallow copies.
(2) Whether the copy function should be customized.
(3) What is called deep copy. What is a shallow copy. The similarities and differences between the two.
A custom copy constructor is a good programming style that prevents the compiler from forming a default copy constructor that increases the efficiency of the source code.
Deep copy: If a class has resources, when the object of this class is replicated, the resource is redistributed, and the process is a deep copy, whereas no reallocation of resources is a shallow copy.
(4) deep copy good or shallow copy good.
If a bit copy is implemented, the value in the object is completely copied to another object, such as A=b. At this point, if a member variable pointer in B has already applied for memory, that member variable in a also points to the same memory. This is the problem: when B releases the memory (e.g., destructor), the pointer in A is a wild pointer, and a run-time error occurs.
4 Copy Assignment operations
Objects are copied not only during the initialization of the construction phase, they can also be copied by any assignment operation. Look at the difference:
MyClass foo;
MyClass Bar (foo); Object initialization: Call copy constructor
MyClass baz = foo; Object initialization: Calling copy constructor
foo = bar; Object has been initialized, call copy assignment
In the above example, MyClass baz = foo; although the equals sign "=" is not an assignment operation (although it looks like): An object's declaration is not an assignment operation, it is just another syntax for invoking a single parameter constructor.
But the operation of this object of Foo is the assignment operation, where there is no declaration of the object, just the assignment of an already existing object.
The copy copy operation of an object is an overloaded form of the operator "=". The return value is a reference to the *this pointer (although there is no requirement here). The syntax is as follows:
myclass& operator= (const myclass&);
A copy assignment operator is a special function that implicitly declares a copy assignment operator if a class does not have a user-defined copy or moves an assignment (or a move constructor).
As with copy assignment operations, a shallow copy is performed. This kind of operation, not only has the deletion object two times, also can cause the memory leak the risk. These problems can be avoided by copying the previous object and performing a deep copy, looking at the following example:
example5& operator= (const example5& x) {
delete ptr; Deletes the string now pointing to
//allocates storage space for the new string, and copies the
ptr = new string (X.content ());
return *this;
}
A better way to do this is to reuse the same string object, based on a string member rather than a constant:
example5& operator= (const example5& x) {
*ptr = x.content ();//point to the same string object return
*this;
}
5 Transfer constructors
Like a copy, a move also sets the value of another object using the value of one object. However, unlike a copy, the move implements a true transfer of the object's value (the source object to the destination object): The source object will lose its content and its contents will be occupied by the destination object. When a move operation occurs, it is when the object that moves the value is an unnamed object.
The unnamed objects here are the temporary variables, not even the names. A typical unnamed object is the return value of a function or the object of a type conversion.
Initializing another object value with the value of a temporary object does not require a copy of the object: Because the temporary object is not otherwise used, its value can be moved to the destination object. To do this, you use the move constructor and move assignment:
When a temporary variable is used to construct an object, the move constructor is invoked. Similarly, when assigning to an object with the value of an unnamed variable, the move assignment is invoked.
MYCLASS fn (); function returns a MyClass object
MyClass foo; Default constructor
MyClass bar = foo; Copy constructor
MyClass baz = fn (); Move constructor
foo = bar; Copy assignment
Baz = MyClass ();
Both the return value of FN and the value of the MyClass construct are temporary variables. In these cases, there is no need to make a copy, because the life cycle of the temporary variable is very short and can be acquired by other objects, and this operation is more efficient.
The following are the syntax for moving constructors and moving assignments, and their return types are the class class itself.
MyClass (myclass&&); Move-constructor
myclass& operator= (myclass&&); Move-assignment
The concept of move operations is useful for objects to manage the storage space they use, such as when objects use new and delete to allocate memory. In such objects, copying and moving are different operations: copying from A to B means that B allocates new memory, and the entire content of a is copied to the new memory allocated for B. The
and moving from A to B means that the memory assigned to a is transferred to B, and no new memory is allocated, it simply contains a simple copy of the pointer.
Look at the following example:
Mobile constructor and 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, parameter x cannot be const pointer&& x,//Because you want to change the value of the member data of X;//c++98 not supported, c++0x (C++11) Support 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"); Constructor Example6 bar = Example6 ("ple"); Move constructor foo = foo + bar; Move assignment cout << "Foo ' s content:" << foo.content () << ' \ n ';
return 0; }
Execution results:
Foo ' s Content:example
The compiler has long been able to optimize most of the forms called mobile constructs using the return value optimization method. Most notably, when a function return value is used to initialize an object. In these cases, the move constructor is not actually invoked.
Note that even if a return value reference can be used as a type of any function parameter, it is not useful for actual use, except for moving the constructor. The return value reference is dangerous, and unnecessary use can be a source of error and very difficult to track.
Summary: Use the scene:
If the second object is a temporary object that is destroyed after the copy or assignment ends, then the move constructor and the move assignment operator are invoked, which benefits from deep replication and increased efficiency.
6 Summary of implied members
The following are the timing of the 6 implied members and the summary of the default definitions
Note that special members that are not in the same class will be implicitly defined. This is mainly for the compatibility of C-structure and earlier versions of C + +, as well as some obsolete classes, and make compromises. Fortunately, each class can explicitly select which members exist with their default definition, or use the keyword default and delete to select them. The syntax is as follows:
Function_declaration = default;
function_declaration = delete;
Default and delete implied members
#include <iostream>
using namespace std;
Class Rectangle {
int width, height;
Public:
Rectangle (int x, int y): width (x), height (y) {}
Rectangle () = default;
Rectangle (const rectangle& Other) = delete;
int area () {return width*height;}
};
int main () {
Rectangle foo;
Rectangle Bar (10,20);
cout << "Bar ' s area:" << bar.area () << ' \ n ';
return 0;
}
The code above, the rectangle class can use either two int parameters or a default constructor to construct the object. But there is no copy constructor, because it has been delete. Therefore, for the object in the example above, the following declaration will be incorrect.
Rectangle Baz (foo);
However, you can explicitly make the above statement legal by defining its copy constructor:
Rectangle::rectangle (const rectangle& Other) =default;
It is essentially equal to the following statement:
Rectangle::rectangle (const rectangle& Other): Width (other.width), height (other.height) {}
Note that the member function defined by the keyword default is not equal to the default constructor (for example, the default constructor means that there are no parameters), but is equal to if there are no implicitly defined constructors that are deleted.
Typically, for future compatibility, classes will explicitly define a copy/move constructor, or copy/move assignment operations, rather than two definitions. This practice is encouraged for other special member functions that you do not want to explicitly define by using delete or default designations.