IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++右值引用和移动构造函数 -> 正文阅读

[C++知识库]C++右值引用和移动构造函数

1.右值引用:

????????我们可能知道函数里的临时对象的生存周期在函数内,也可能更详细的知道临时对象离开它的作用域就会消亡,不过我们平时可能很少直观感受到这一点。因此我们想象下面一个场景,如果我们想要定义一个int*类型返回值的函数,该函数构建一个int类型的值。此时我们一般采用如下方式写:

int* func() {
    return new int(1);
}

????????这样我们就可以得到一个动态内存,因此我们需要在调用完返回值后delete释放内存(当然可以使用智能指针)。不过很多时候我们不喜欢使用动态内存,然后我们想到了在函数里构建一个int变量并返回其地址,如下:

int* func(bool flag) {
    int a=1;
    return &a;
}

int main() {
    int* p=func(true);
    if(p==nullptr) {
        std::cout<<"nullptr";
    }
    return 0;
}

????????这样看起来不错,但是当我们运行起来会发现返回的p是nullptr,而不是1。结合临时对象我们此时可能明白了,a在func结束之后就会被回收。那么此时我们好像只剩下两个选择,要么返回一个new的对象,要么就在函数外构建变量然后函数内赋值。此时我们可能会想如果能够延长a的生存期到p的生存期结束就好了,而右值引用可以延长生存期。

????????我们先看看右值引用的基本用法

int a=2;
int&& b=std::move(a);
int *p=b;
std::cout<<a<<' '<<b<<' '<<*p<<'\n';  //输出2 2 2

int&&d =0;
d+=1;
std::cout<<d<<'\n'; //输出1

? ? ? ? 第二行的std::move使得右值引用可以指向左值。我们发现左值引用无法指向右值,但是右值引用通过std::move可以指向左值。右值引用可以指向右值,也可以被指针取地址。我们再用如下方式实现上述问题:

int&& get() {
    int a=1;
    return std::move(a);
}

int* getPtr() {
    int&& a = get();
    return &a;
}

int *p=getPtr();

? ? ? ? 此时p已经指向int型的1了,这样我们也直观验证了右值引用可以延长对象生存周期的特点。

2.移动构造函数:

? ? ? ? 上文简单介绍了右值引用的一些特点,但是右值引用最大的用处(可能没有之一)在于构建移动构造函数来减少拷贝次数。

2.1 深拷贝:

? ? ? ? 简单的说如果类里面有指针,那么浅拷贝就是只拷贝指针,拷贝者和被拷贝者指向同一个地址。深拷贝就是构造一个等大的内存,然后从被拷贝者指针指向的内存复制数据到自己中。如下伪代码:

class node {
public:
    int size;
    int* ptr;
    node() :size(0), ptr(nullptr) {};
    node(const node& otherNode) {
        size = otherNode.size;
        ptr = new int[size];
        for (int i = 0; i < size; i++) {
            ptr[i] = otherNode.ptr[i];
        }
    }
    node& operator=(const node& otherNode) {
        size = otherNode.size;
        ptr = new int[size];
        for (int i = 0; i < size; i++) {
            ptr[i] = otherNode.ptr[i];
        }
    }
};

? ? ? ? 我们需要拷贝ptr指向的所有内容,但是很多时候我们赋值之后就不需要nweNode了,因此我们可能会想如果能直接接管newNode的内容就好了。但是我们不能直接让newNode.ptr=nullptr,因为不是所有的赋值操作后newNode就不需要了,因此我们需要使用新的函数进行移动构造。

2.2 尝试使用左值引用来进行移动构造:

? ? ? ? 我们第一反应就是构建如下拷贝构造函数:

node(node& otherNode);

? ? ? ? 然而我们传递的是左值,这意味着我们不能使用下面方式进行构造:

node a(node());

? ? ? ? 因为左值引用不能接收右值,而形如node()这类函数显然是右值。因此我们想到const引用可以指向右值,因此想到下面形式:

node(const node& otherNode);  //与深拷贝重定义,想到下列方式
node(const node& otherNode, char arg);

? ? ? ? 我们又得到一个新的方式,但是首先我们需要传递一个无用参数arg,它仅仅用来区分深拷贝。此外,当我们实现时会发现由于是const引用,因此我们不能修改otherNode,进而就不能写以下语句:

otherNode.ptr=nullptr;

? ? ? ? 这样左值引用方式基本宣告失败。因此引入了右值引用。

2.3 右值引用实现的移动构造函数:

? ? ? ? 我们直接上代码:

node(node&& otherNode) {
    size = otherNode.size;
    ptr = otherNode.ptr;
    otherNode.ptr=nullptr;
}
node& operator=(node&& otherNode) {
    size = otherNode.size;
    ptr = otherNode.ptr;
    otherNode.ptr=nullptr;
}

? ? ? ? 这样我们就成功接管了otherNode,没有使用任何拷贝。因此我们可以如下方式调用:

node a;
node b;
node c=a;
node d=std::move(b);

? ? ? ? 第三行为深拷贝,第四行为浅拷贝,直接接管b。

2.4 移动构造函数的注意事项:

? ? ? ? 当我们没有定义移动构造函数时,我们采用移动拷贝时会执行默认的拷贝构造函数,即便我们使用下面写法:

node(node&& otherNode)=default;

? ? ? ? 它调用的仍是默认的拷贝构造函数node(const node& otherNode),当默认拷贝构造函数=delete时它也无法调用。但是当默认拷贝构造函数delete时,我们可以写移动构造函数并进行移动构造。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:37:29  更:2022-04-28 11:38:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 23:07:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码