127-C++ learning fifth bullet

The characteristics of the constructor: It will be automatically transferred, and you cannot actively transfer the constructor. The
constructor takes an integer data to initialize the object, that is, the built-in type
copy constructor takes one object to initialize another object space, and it lives at 1. When the actual parameter object and the formal parameter object are combined, 2.return returns an object

Int fun(Int x)
{
    
    
	int a=x.Value();
	Int tmp(a);
	return tmp;
}

int main()
{
    
    
	Int a(10);
	Int b;
	b=fun(a);

	return 0:
}

When it is an actual parameter object and initializes a formal parameter object, the copy constructor will be invoked. When return tmp; we want to return a temporary object, we must invoke the copy constructor to construct a temporary object as a return. Because tmp cannot be directly given to the b object, if tmp is directly given to the b object, it will cause tmp to survive in both functions. This is the same as our local object can only be valid in the function when the function is invalid. Here, there is a concept: death value. When returning to tmp, we will construct a temporary object in the stack frame of the main function. When the temporary object is assigned to b, the lifetime of the temporary object will come. We call this object the dead value

Destructor features: release an object and release the resources it is in.
Default function: if you don’t write a constructor, the system will give you a default constructor (just create the object, you cannot initialize the object itself, the data is a random value) , Copy constructor (grab the address of the object, grab the address of the object to be constructed, and copy it bit by bit)

Int& operator=(const Int& it)
{
    
    
}//a=b

Default constructor : grab the address of b, grab the address of a, copy the content of b to b byte by byte, copy by bit

Sometimes the default copy constructor can meet our requirements, and sometimes it can’t. If we don’t apply for resources, we can meet our requirements. If we want to apply for resources, then we can’t meet our requirements.

Int& operator=(const Int& it)
	{
    
    
		if (this != &it)//防止自己给自己赋值,a=a
		{
    
    
		value = it.value;
		}
		cout << this << " = " << &it << endl;
	return *this;
}//a=b

The assignment statement here returns a reference to a type. Why do you return a reference to its own type here? a=b; returns this pointer, this pointer points to a, *this is the a object itself, and returns itself as a reference. When the function dies, the this pointer also dies, and the object a pointed to by this is not affected by this function Impact, when this function ends, the a object still exists, so it can be returned by reference. The overloading of our operators, we hope that the ability of the overloaded operator is close to its ability for built-in types. In order to realize a=b=c, the ability of continuous assignment. a=operator=(&b,c); b mobilizes the assignment statement, passes the address of b into it, as a member function, contains this, takes c to initialize it, it is the alias of c, this points to the address of b, and returns * this, is the b object, assign the b object to a

Int a(a); The compiler will give you an error when compiling, because you haven't finished constructing a, how can you build it for yourself?

void SetValue(int x) {
    
     value = x; }
int GetValue() const {
    
     return value; }

int& Value() {
    
     return value; }

int& Value() {return value;} can take value and assign value

int main()
{
    
    
	Int a(10);
	Int x=a.Value();
	a.Value()=100;//把100赋值给Value()的返回值,这个返回值Value对象也就是a的别名 被系统解释成a.value=100;
	return 0;
}

For ordinary objects, you can call it.
If const Int a(10); becomes a constant object, it means that the property value in a cannot be changed. When the value is transferred to return by ordinary reference, the value can be changed, resulting in contradiction and grammatical ambiguity.
Such functions generally appear in pairs

const int& Value() {
    
     return value; }
const Int a(10); 

Common object calls common object method
Common object calls common method

int funa()
{
    
    
	int tmp = 10;
	return tmp;
}
int main()
{
    
    
	int x=0;
	x=funa();
	cout<<x<<endl;
	return 0;
}

funa() creates an integer variable, return tmp, and constructs a temporary variable as a transition.
When our program starts to execute, the main function is executed. The compiler finds that it is a built-in type, and assigns a stack frame to the main function. x variable, mobilize funa, allocate a stack frame in funa, define a tmp=10; return tmp; put the value of tmp 10 in eax, and then return tmp of funa; it means it is over, and the stack frame assigned to it is over , When returning to the main function, give the value obtained by register eax to x
Insert picture description here

If the reference to receive int &x=funa(); is problematic , the reference is equivalent to an alias. When the system is compiled, the reference is compiled into a pointer. When we mobilize funa, we define a tmp=10;return tmp; we In the register eax, the integer value of tmp is placed. This reference, thinking about pointing to eax or this 10, is not allowed, the concept of dead value (cannot take the address)

 const int &x=funa();  

The above method is possible, universal reference. Although the value returned to eax is
equivalent to executing
int tmp = eax;
const int &x = tmp;
here is a memory space of the main function

The following method is also possible! Rvalue references

int&& x = funa();
// int tmp = eax;
// int &&x = tmp;

The lifetime of this death value becomes the same as x

The following code is very important

int& fun()
{
    
    
	int x = 10;
	return x;
}

int main()
{
    
    
	int a=fun();
	int&b=fun();
	cout<<a<<endl;//打印出10
	cout<<b<<endl;//打印出随机值
	return 0;
}

But this code is wrong!
The problem of lifetime
If you want to return a value by reference, the lifetime of this data or this variable or this object is not limited by the fun function, that is, when you return by reference, when the fun function ends, x The lifetime of this variable has not expired, and x is still alive. If you want to return a variable to its address or return its reference, the lifetime of the variable is not affected by this function. In
this example, x is returned, and the lifetime of x is affected by the fun function, fun() When it is over, the lifetime of x is over. When the program is running, the main function is running, assign a stack frame to the main function, define a variable a, at this time a has no value, call fun(), allocate a space for fun, define x=10; return x to reference Return, the essence of the reference is interpreted by the system as an address, eax stores the address of x, return x; when the end, the stack frame allocated to fun is destroyed, and eax points to this space. Although this space has expired, a is an integer variable. It is impossible to store eax. This step is explained systematically: a=*eax; here is a question: Is this space protected from intrusion? If you are not disturbed, you can read 10, if you are disturbed, you can't read 10, where b is a reference, in fact, b is a pointer, and what is returned is a reference, the address of x, and the address of b points to x. When printing a, The value of a has been obtained. When printing b, it is printed by pointing. The cout itself is the output function (opening up the stack frame and covering the space of the original fun function), which invades this memory area, so the random value is printed.
Single-threaded assignment is not disturbed.
Multi-threaded assignment may be interrupted by certain errors
Insert picture description here
. When printing, 10 has been copied to a, intruding it, a is already 10, and b has not copied this value

Int fun()
{
    
    
	Int a(10);
	return a;
}
int main()
{
    
    
	Int x=fun();//OK
}

When we mobilize fun(); to produce an object a, and when it returns, a temporary object a is produced, the function fun ends, the a object dies, and the temporary object a is copied to construct x

Int &x=fun();//error

The reason for the error: the temporary object a is a dead value and cannot refer to a dead value.
After the function ends, the temporary object will be destructed, and the grammar rules do not allow

const Int &x=fun();//ok

Constant reference, refer to the object it constructed, this refers to the temporary object of this main function, this cannot change it

Int&&x=fun();//ok

Rvalue reference Quoting will die value. The
Insert picture description here
Insert picture description here
system has a default assignment statement.
Insert picture description here
When assigning a value, the system’s default assignment statement is to grab the address of a and b, copy the value of a, and print 10, but it’s wrong .
Because when a is created, when the assignment statement is called, the original fun space will be shuffled again, and the value of a will be overwritten.
Insert picture description here
What is printed is still a random value and the
returned object reference has died

class String
{
    
    
	char* str;
public:
	String(const char* s = nullptr)
	{
    
    
		if (s != nullptr)
		{
    
    
			int len = strlen(s);
			str = new char[len + 1];
			strcpy_s(str, len + 1, s);
		}
		else
		{
    
    
			str = new char[1];
			*str = '\0';
		}
	}

	~String()
	{
    
    
		if (str != nullptr)
		{
    
    
			delete[]str;
		}
		str = nullptr;
	}
};

The system default default copy constructor
Insert picture description here

String(const String& st)//浅拷贝
	{
    
    
		str = st.str;
	}

Deep copy
Insert picture description here

String(const String& st)//深拷贝
	{
    
    
		int len = strlen(st.str);
		str = new char[len + 1];
		strcpy_s(str, len + 1, st.str);
	}

Insert picture description here
When assigning s1 to s2, the default assignment function assigns the str value of s1 to the str of s2, causing the str of s2 to be pointed directly. What is wrong with this?
1. Memory leak 2. When the s2 object is destructed, the program crashes and is released twice

	String& operator=(const String& st)
	{
    
    
		str = st.str;
		return *this;//按位赋值,缺省构造
	}

Assignment function written by yourself

String& operator=(const String& st)
	{
    
    
		if (this != &st)
		{
    
    
			delete[]str;
			int len = strlen(st.str);
			str = new char[len + 1];
			strcpy_s(str, len + 1, st.str);
		}
		return *this;
	}

Insert picture description here

The main function allocates a random value of s1 (not constructed) and str. When we call fun(), allocate a stack frame, s, str, allocate a space from the heap area, copy yhpinghello to it, and return it normally. Press The value is returned, a temporary object is constructed, the copy constructor is invoked, and the temporary object str also points to a heap space yhpinghello. After the temporary object is constructed, the function will end, and the lifetime of s is up. Call the destructor to release the space, and the heap does not Exist, when returning to the main function, this temporary object needs to build s1, open up space, copy yhpinghello in, and then the temporary object lifetime is up, and the destructor is released. This method creates multiple objects, which is inefficient.
Insert picture description here

Mobile structure

The mobile structure of the system

	String(String&& s)
	{
    
    
		str = s.str;
		//delete[]s.str;
		s.str = nullptr;
	}

Returning an s is to return a dead value. The system initializes s to s of String(String&& s), mobilizes the movement structure, moves
Insert picture description here
the resource to transfer the resource of the s object to s1, and sets s.str to empty
to make the local object The
Insert picture description here
two writing methods are different
. The first writing method is to take the returned object to construct s1, mobilize the mobile structure, and give the resource of s to s1. The
second method does not mobilize the mobile structure. The constructor is to create the object , The copy constructor is also to create an object, and the move construction is also to create an object, but the s2 object already exists, so move the assignment function

String& operator=(String&& s)
	{
    
    
		if (this != &s)
		{
    
    
			delete[]str;
			str = s.str;
			s.str = nullptr;
		}
		return *this;
	}


Insert picture description here
If the original method has a move structure, it is convenient and
Insert picture description here
equivalent

return s; Use the move construction to construct a temporary object. The str pointer of the temporary object points to the yhpinghello of the s object and the str of s is set to null. When the function is constructed, the s object is destroyed, and it will not be released by yphinghello. Return to the main function. Transfer the dead value to the move assignment statement, at this time s is the alias of move assignment.
Insert picture description here
This method new space is only new once.
The return value s is directly constructed s1 (mobile construction)
Insert picture description here

Mobile constructor, mobile assignment function system has, but if you want to use it, you have to implement it yourself

Guess you like

Origin blog.csdn.net/LINZEYU666/article/details/112111388