Overview
Starting in C + + 11, the language supports two types of allocations: copy assignment and move assignment . What are the internal details? It's a pretty interesting process to follow up today. Let's do an analysis with a simple class.
#ifndef Hasptr_h#defineHasptr_h#include<string>classHasptr { Public: FriendvoidSwap (hasptr&, hasptr&); Hasptr (ConstSTD::string& s = std::string()); Hasptr (Consthasptr&hp); Hasptr (Hasptr&&p) noexcept; Hasptr&operator=(hasptr RHS); //hasptr& operator= (const hasptr &RHS); //hasptr& operator= (hasptr &&rhs) noexcept;~hasptr ();Private: std::string*PS; inti;};#endif //Hasptr_h#include"Hasptr.h"#include<iostream>inlinevoidSwap (hasptr& LHS, hasptr&RHS) { usingStd::swap; Swap (lhs.ps, rhs.ps); Swap (lhs.i, rhs.i); Std::cout<<"Call swap"<<Std::endl;} Hasptr::hasptr (ConstSTD::string& s): PS (NewSTD::string(s)), I () {std::cout<<"Call Constructor"<<Std::endl;}//here the i+1 just for the convenience of debugging time to see the process, actually do not add 1Hasptr::hasptr (Consthasptr& hp): PS (NewSTD::string(*hp.ps)), I (HP.I +1) {Std::cout<<"Call copy Constructor"<<Std::endl;} Hasptr::hasptr (Hasptr&&p) noexcept:ps (p.ps), I (P.I) {p.ps=0; Std::cout<<"Call Move Constructor"<<Std::endl;} Hasptr& Hasptr::operator=(hasptr rhs) {Swap (* This, RHS); return* This;} Hasptr::~hasptr () {std::cout<<"Call destructor"<<Std::endl; DeletePS;}
Main function
int Main (intChar *argv[]) { qcoreapplication A (argc, argv); Hasptr HP1 ("hello"), Hp2 ("World"new Hasptr ("World"); = Hp2; = Std::move (*pH); return a.exec ();}
Here we start debugging:
Output:
We construct three variables with constructors, their values and
|
Address |
Ps |
I |
Hp1 |
0x28fe64 |
"Hello" |
0 |
Hp2 |
0x28fe5c |
"World" |
0 |
Ph |
0x28fe9c |
"World" |
0 |
Copy Assignment
We then go one step further:
It can be found that the copy constructor was called first, and a temporary variable like HP2 was constructed.
|
Address |
Ps |
I |
This |
0x28fe2c |
"World" |
1 |
Hp2 |
0x28fe5c |
"World" |
0 |
Next:
Before we begin the assignment operation, we compare the data:
|
Address |
Ps |
I |
This |
0x28fe2c |
"Hello" |
0 |
Rhs |
0x28fe8c |
"World" |
1 |
The RHS here is the temporary variable we just assigned, so this is HP1, so finally our temp variable and HP1 exchange, we go on:
Here LHS address is: 0x28fe64, is the address of HP1, after Exchange:
The values for this HP1 and temporary variables are completely exchanged, meaning Hp1 = hp1.
|
Address |
Ps |
I |
Lhs |
0x28fe64 |
"World" |
1 |
Rhs |
0x28fe8c |
"Hello" |
0 |
But then we ran and found a destructor:
Look at the address is 0x28fe8c and its value, this is a temporary variable, the temporary variable is not used, so it was destroyed, so that our copy assignment Operation is over.
Move Assignment
Let's take a look at the assignment of the assignment value:
The first step is to move the function, where the pointer points to the PH data, not the new data, the right value of the variable refers to the ph, just the equivalent of changing a name.
Next, proceed to the assignment operation:
Here the values of the two interchanges are HP1 and ph, and the copy assignment is different, it is exchanging data with the temporary variable,
Go back to the destructor:
It releases the ph data.
As you can see, the ph value is released.
Summary
After debugging, we found that the assignment operation was not as simple as imagined, was it? Copying an assignment or creating a temporary variable for conversion, which consumes extra space resources.
Moving the assignment avoids this problem, but it is important to note that the move assignment uses the right value and is destroyed after it is exhausted, so if you want to use an lvalue as an rvalue, you must make sure that the lvalue is not used after that.
Reference:
- "C + + Primer"
Thinking of "Copy assignment" and "Move Assignment"