😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- ✨1.1 移动语义
- ✨1.2 右值引用
- 🎄二、移动构造函数(move constructor)
- 🎄三、使用移动构造函数
- 🎄四
- 🎄五
- 🎄六、
🎄一、概述
移动构造函数、移动赋值函数都是C++11增加的,了解这两个函数之前需要先弄清楚 移动语义 和 右值引用。
✨1.1 移动语义
移动语义是C++11才实现的,它的意义是对于一些即将被销毁的对象,可以不复制它,而是窃取它的资源,以此来减少一次复制,达到大幅度提升性能的效果。
在C++11标准之前,没有直接的方法移动对象,即使某些情况不需要拷贝对象,也不得不拷贝。例如,函数返回非引用的返回值时,会先构造一个临时对象作为返回值,函数调用时将该临时对象赋值给接收对象,调用结束后会销毁该临时对象。这里的临时对象是肯定会被销毁的,如果能够将临时对象的资源直接移交给接收对象,那么就可以减少一次拷贝。旧标准则只能拷贝,然后再销毁临时对象的资源。
C++11支持将即将被销毁的对象移动到接收对象,而不是复制。如下图,临时对象的资源被移动到接收对象,减少一次复制。
下面代码演示了复制的过程,等学习了下面的移动构造函数就可以编写移动的代码了。
// g++ 11_Copy_Constructor_Date.cpp
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;#define MAX_NEW_MEM (64*1000*1000)class CDate
{
public:CDate(int year, int mon, int day); // 构造函数声明CDate(const CDate& date); // 拷贝构造函数声明~CDate(); // 析构函数声明CDate operator+(int day); // 加号运算符声明void show(){cout << "Date: " << m_year << "." << m_mon << "." << m_day << ", this=" << this << endl;//cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[MAX_NEW_MEM];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 拷贝构造函数定义
CDate::CDate(const CDate& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[MAX_NEW_MEM];memcpy(str, date.str, MAX_NEW_MEM);cout << "Calling Copy Constructor" << ", this=" << this << ", Copy Data" <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}CDate CDate::operator+(int day)
{CDate temp = *this;temp.m_day += day;cout << "Calling operator+" << ", this=" << &temp << endl;return temp;
}int main()
{CDate date(2024,06,07);cout << endl;CDate date1 = std::move(date+1);// std::move 强制将 date+1 的求值结果转为右值date1.show();cout << endl;return 0;
}
运行结果如下:
1、std::move 强制将 date+1 的求值结果转为右值,避免编译器优化;
2、temp 对象赋值给date1之后,就销毁了,如果可以直接将temp对象的资源给到date1,就可以减少一次复制。
✨1.2 右值引用
前面介绍了C++11的移动语义,那这个移动语义是怎样实现的呢?
C++11标准引入的一种新的引用类型——右值引用,来实现移动操作。右值引用只能关联到右值,而右值要么是字面值,要么是求值过程中产生的临时对象。右值引用的定义使用了&&
,可以参考下面代码:
int &&rri = 13; // 定义了右值引用 rri
上个小节的临时对象只会在程序中很短暂的停留,使用完之后会被立即销毁。C++11标准通过 右值引用 来完全地接管这些临时对象,然后将临时对象的资源 移动 到接收对象,并且要保证这个临时对象可以被正常销毁。这就是C++11标准实现移动语义的原理。
关于左值、右值、右值引用还有疑惑的,可以参考这篇文章:【C++ | 左值、右值】一文了解C++的左值、右值、左值引用(&)、右值引用(&&)
🎄二、移动构造函数(move constructor)
移动构造函数(move constructor),是C++11标准增加的在创建对象时移动旧对象资源的构造函数。
类的移动构造函数原型通常是这样的:类名(类名 &&);
。以CDate
类为例,其移动构造函数声明如下:
CDate(CDate &&date);
移动构造函数的几个特点:
1、函数名和类名相同,因为它也是构造函数的一种;
2、第一个参数必须是一个自身类类型的右值引用,且其他参数都有默认值。
3、第一个参数不能声明为 const 右值引用的原因是该引用在函数内会被修改(移动资源)。
4、移动构造函数执行后,需要保证右值引用的对象能够被正常销毁。
下面看看怎样声明定义自己的移动构造函数:
CDate::CDate(CDate&& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = date.str;date.str = NULL;cout << "Calling Move Constructor" << ", this=" << this <<endl;
}
语句str = date.str;
将旧对象的str直接给到正在创建的对象,而不重新new、复制。
语句date.str = NULL;
将旧对象的str赋值为NULL,保证其可以被delete。
🎄三、使用移动构造函数
🎄四
🎄五
🎄六、
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁