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++实践1:RVO优化 -> 正文阅读

[C++知识库]C++实践1:RVO优化

一.问题引入

1. 如下代码会输出什么?

class String{
public:
    explicit String(const char* p){
        size_t size = std::strlen(p) + 1;
        data = new char[size];
        std::memcpy(data,p,size);
        cout<<"1"<<endl;
    }

    ~String(){
        delete[] data;
    }

    String(const String& that){
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        std::memcpy(data,that.data,size);
        cout<<"2"<<endl;

    }
private:
    char* data;
};

int main(){
    auto temp = String(String("hi"));
    return 0;
}

2.答案

在这里插入图片描述

3. 代码解读,问题提出

  • 定义了两个String构造函数,一个使用const char*进行初始化,另一个使用String变量进行拷贝初始化
  • 主函数里,我们用const char*“hi”初始化了一个临时String变量, 再用这个临时String变量初始化另一个String变量
  • 如果是按照上述思路执行的话,应该是输出1和2和2,但是最后只输出了1,说明,没有执行临时量copy的过程,问题出在哪了?编译器优化?

二.借助汇编分析问题

1. 命令

g++ -o main.s -S main.cpp

2.内容如下

  • const char* 构造函数
    在这里插入图片描述
  • main函数
    在这里插入图片描述

3.汇编代码解读

  • 保存寄存器入栈

  • 开辟24字节的栈空间,
    在这里插入图片描述

  • 其中24字节用于存储金丝雀值(不知道金丝雀的可以去百度)
    在这里插入图片描述

  • 随后8字节,存储的是temp类,记住,类成员函数不占空间,我们的类A,sizeof(A) == 8
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

4. 汇编层面解释调用成员函数

多说一句,类的成员函数如何被调用

  • 其实成员函数存储在.text节中,
  • 我们调用成员函数时,先在栈/堆上分配sizeof(类)的空间(设其地址为A),空类大小为1(而不是0),
  • 此时这个空间的地址(地址A),就代表了this指针,
  • 我们将这个A(或称为this指针),传递到.text节中的某个成员函数,
  • 成员函数隐式的第一个参数就为this,所以成员函数可以区分是哪个类在构造对象或调用对象,
  • 成员函数随后在this(A地址)上进行各种操作,就是对A这块地址操作,就是对我们分配出的类实例在操作
  • 不同的类实例有不同的this,即有不同的地址空间,所以我们可以使用一个成员函数操纵所有的类

5. 本函数调用的构造函数

在这里插入图片描述

可以看出,是const char*,而随后并没有再调用其他的构造函数了。
为什么没有调用拷贝构造函数?
原来是编译器帮我们做了优化!!!

三.问题解答:RVO优化

1. RVO优化是什么

  • 返回值优化,return value optimization, 这是一种编译器优化机制,当函数返回一个对象的时候,如果自己创造一个临时对象进行返回(对应于main函数里,我们的String("hi")),那么这个临时对象会消耗一个构造函数的调用(String(const char*)),一个复制构造函数的调用(String(const String& s)),以及一个析构函数的调用(析构掉临时值)

  • 经过返回值优化,就可以将成本降低到一个构造函数的代价。这样就省去了一次拷贝构造函数的调用和依次析构函数的调用。

  • 注意从C++17开始,RVO优化不再是可选的,而是默认的

2. 关闭RVO优化

-fno-elide-constructors选项可以取消编译器的 copy-elision 优化策略

3. NRVO优化是什么

  • (Named Return Value Optimization)。具名返回值优化(NRVO),是对于按值返回“具名对象”(就是有名字的变量)时的优化手段,其实道理是一样的,但由于返回的值是具名变量,情况会复杂很多。所以,能执行优化的条件更苛刻。

4. 结合本例谈RVO优化底层如何实现

  • 其实从上面我们对于汇编代码的讲解就已经提到了
  • 我们直接从temp的地址进行构造,而不是先构造出一个临时变量,再把该变量的地址传给temp的拷贝构造函数,
  • 编译器采取的是直接把“hi”的地址传给temp
  • 编译器足够智能!!!

四. 验证结果

1. 关掉RVO优化

在这里插入图片描述

  • 输出了1,2,2
  • 第一个2:临时变量传入拷贝构造函数,作为拷贝构造函数的参数
  • 第二个2:构造完成,赋值给temp,调用拷贝构造函数

2. 查看底层汇编

  • main函数的汇编语句
  • 自己去尝试实现,读个两遍,再来看下面解释
    在这里插入图片描述
  • 可以看出,关闭优化后,拷贝构造函数也被加入了.text中,命名为_ZN6StringC1ERKS_
  • 调用顺序也是符合预期
  • 说明我们最开始的问题得到了验证。
  • 如有错误,欢迎指正。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 22:56:03  更:2021-07-22 22:56:34 
 
开发: 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/2 4:55:27-

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