C++11之右值引用、移動語義

guojawee發表於2018-12-06

本文涉及的概念:
1. 右值引用
2. std::move
3. 移動建構函式、移動賦值函式


右值引用的主要目的之一是實現移動語義。

1、為什麼使用移動語義?
避免拷貝帶來的開銷

2、std::move
功能:將引數從左值變成右值,使得引數為左值時呼叫移動語義的函式來避免開銷
詳細解釋:因為傳遞的引數如果是左值,將會呼叫拷貝構造、拷貝賦值函式,但是使用std::move將引數轉換成右值後,將會呼叫移動拷貝構造、移動賦值函式。

3、示例程式碼
看程式碼可以看到:
① 移動建構函式、移動賦值函式:進行深拷貝,在賦值
② 拷貝建構函式、拷貝賦值函式:轉換所有權,不經過拷貝

那麼是呼叫移動語義的函式?還是呼叫拷貝語義的函式?
編譯器會判斷傳入引數是左值?還是右值?,呼叫相對應的函式;當想讓傳入左值時,呼叫移動語義的函式,先使用std::move將左值轉換成右值。

/*
右值引用的主要目的:移動語義,將b的控制權轉交給a
避免拷貝過程帶來的開銷,提高效率
*/

#define _CRT_SECURE_NO_WARNINGS
#pragma once

#include<iostream>
#include<vector>
using namespace std;

class MyString{
public: 
	MyString();
	MyString(int len);
	MyString(const char* str);
	~MyString();
public:
	MyString(const MyString& another); //預設拷貝構造
	MyString& operator=(const MyString& another);//預設賦值
public:
	MyString(MyString&& another); //移動拷貝構造
	MyString& operator=(MyString&& ano);//移動賦值
public://運算子過載
	MyString operator+(const MyString& another);
	MyString& operator+=(const MyString& another);
	bool operator==(const MyString& another);
	bool operator!=(const MyString& another);
	char& operator[](int index);
	friend ostream& operator<<(ostream& cout, const MyString& myStr);
	friend istream& operator>>(istream& cin, MyString& myStr);
private:
	int len;
	char* str;
};
MyString::MyString(){
	cout << "建構函式" << endl;
	this->len = 0;
	this->str = NULL;
}
MyString::MyString(int len){
	cout << "建構函式" << endl;
	this->len = len;
	this->str = new char[len + 1];
	memset(this->str, 0, sizeof(this->str));
}
MyString::MyString(const char* str){
	cout << "建構函式" << endl;
	if (str == NULL){
		this->len = 0;
		this->str = new char[0 + 1];
		this->str = '\0';
	}
	this->len = strlen(str);
	this->str = new char[this->len + 1];
	strcpy(this->str, str);
}

MyString::~MyString(){
	cout << "解構函式" << endl;
	if (this->str != NULL){
		delete[] this->str;
		this->str = NULL;
		this->len = 0;
	}
}

MyString::MyString(const MyString& another){
	cout << "預設拷貝構造" << endl;
	this->len = another.len;
	this->str = new char[this->len + 1];
	strcpy(this->str, another.str);
}
MyString& MyString::operator=(const MyString& another){
	cout << "預設賦值" << endl;
	if (this != &another){//判斷拷貝自身
		if (this->str != NULL)//釋放自身垃圾
			delete[] this->str;
		//深拷貝
		this->str = new char[another.len + 1];
		strcpy(this->str, another.str);
		this->len = another.len;
	}
	return *this;//返回物件本身
}

MyString::MyString(MyString&& another){
	cout << "移動拷貝構造" << endl;
	//ano.str的控制權轉移給this->str
	this->str = another.str;
	another.str = NULL;
}
MyString& MyString::operator=(MyString&& ano){
	cout << "移動賦值" << endl;
	if (this != &ano){
		if (this->str != NULL)
			delete this->str;
		//ano.str的控制權轉移給this->str
		this->str = ano.str;
		ano.str = NULL;
	}
	return *this;
}

MyString MyString::operator+(const MyString& another){
	char* tmp = this->str; //臨時變數指向this
	this->len += another.len;
	this->str = new char[this->len + 1];
	strcpy(this->str, tmp);
	strcat(this->str, another.str);
	if (tmp != NULL){
		delete tmp;
		tmp = NULL;
	}
	return *this;
}
MyString& MyString::operator+=(const MyString& another){
	char* tmp = this->str; //臨時變數指向this
	this->len += another.len;
	this->str = new char[this->len + 1];

	strcpy(this->str, tmp);
	strcat(this->str, another.str);
	if (tmp != NULL){
		delete tmp;
		tmp = NULL;
	}
	return *this;
}
bool MyString::operator==(const MyString& another){
	return strcmp(this->str, another.str);
}
bool MyString::operator!=(const MyString& another){
	return !strcmp(this->str, another.str);
}
char& MyString::operator[](int index){//注意返回值char&
	if (index > this->len)//索引越界判斷
		exit(-1);
	else
		return this->str[index];
}
ostream& operator<<(ostream& cout, const MyString& myStr){
	cout << myStr.str;
	return cout;
}
istream& operator>>(istream& cin, MyString& myStr){
	//1.釋放myStr之前的字串
	if (myStr.str != NULL){
		delete[] myStr.str;
		myStr.str = NULL;
		myStr.len = 0;
	}
	//2.通過cin新增新的字串
	char buf[4096] = { 0 };
	cin >> buf;
	myStr.len = strlen(buf);
	myStr.str = new char[myStr.len + 1];
	strcpy(myStr.str, buf);
	return cin;
}

void test01(){
	MyString st1("ABC");
	MyString st2(st1);
	MyString st3(std::move(st1));
}
void test02(){
	MyString a("11");
	MyString b("22");
	a = b;
	a = std::move(b);
}
int main(){
	test01();
	test02();
}

相關文章