C++成员初始化列表

news/2024/5/17 14:03:44

我们在类的构造函数中使用成员初始化列表可以带来效率上的提升,那么成员初始化列表在编译后会发生什么就是这篇文章要探究的问题

文章目录

  • 引入
  • 成员初始化列表
    • 用成员初始化列表优化上面的代码
    • 成员初始化列表展开
    • 成员初始化列表的潜在危险
  • 参考资料


引入

考虑下面这个例子

#include <iostream>
using namespace std;class String {int len;
public:String() {len = 0;}String(int l) {len = l;}String(const String& str) {len = str.len;}
};class Word {String _name;int _cnt;
public:Word() {_name = 0;_cnt = 0;}
};
int main()
{Word word;
}

其在VS2022下的汇编码,可以看到在 Word 的默认构造函数中调用了 String 的两个构造函数,分别是默认构造函数和带参数的构造函数

这里在 [rbp+0C4h] 的位置即 _name=0 右边的 0 作为临时 String 类对象,调用带参数的构造函数,然后将 [rbp+0C4h] 里的值逐位拷贝至 [this] 位置(首位置就是成员 _name的位置),相当于是编译器合成了默认的赋值运算符

其编译器对上述Word默认构造函数中代码的扩张结果可能如下:

Word::Word()
{_name.String::String();	String temp = String( 0 );_name.String::operator=( temp );temp.String::~String();_cnt = 0;
}

成员初始化列表

用成员初始化列表优化上面的代码

上面的代码我们可以用成员初始化列表进行优化

Word::Word : _name( 0 )
{_cnt = 0;
}

它会被扩张成下面的样子

Word::Word()
{_name.String::String( 0 );_cnt = 0;
}

汇编代码可以看到只调用了一次带参的构造函数,且可以看到是在 _cnt=0 之前先进行了 _name 的初始化


成员初始化列表展开

当然我们也可以将两个变量全用成员初始化列表实现

Word::Word() : _cnt(0), _name(0)
{}

编译器会逐个操作初始化列表,以适当的次序在构造函数内安插初始化操作,并且位于任何显式的用户代码之前,例如上面的代码会扩充为:

Word::Word()
{_name.String::String( 0 );_cnt = 0;
}

可以看到扩充代码是以类中成员变量的声明次序决定,不是由初始化列表的排列次序决定,下面的汇编代码也验证了这一点。


成员初始化列表的潜在危险

如果类中成员变量的声明次序与初始化列表中的项目排列次序是混乱的或是有差异的,可能会导致意想不到的问题。

考虑下面这个例子:

class X {
public:int i;int j;
public:X(int val) : j(val), i(j) {}
};

我们在写这个构造函数的本意可能是想先用 val 初始化 j 再用 j 来初始化 i,我们用 1 来初始化,然后输出 x.ix.j

可以看到结果不是我们希望的那样,因为正如前面所述,成员初始化列表会以变量声明顺序进行初始化,而不是初始化列表中的排列顺序。

我们可以改为下面的代码,就没有问题,因为合成的代码会插入到用户显式的代码之前。

class X {
public:int i;int j;
public:X(int val) : j(val) {i = j;}
};

如果一个派生类成员函数被调用,其返回值当作基类构造函数的一个参数,将会如何:

class FooBar : public X {int _fval;
public:int fval() {return _fval;}FooBar( int val ) : _fval( val ), X ( fval() ) {} 
}

它的可能扩张结果如下,也不是一个好主意

FooBar::FooBar ()
{X::X( this, this->fval() );_fval = val;
}

以 1 作为初始化参数,然后顺序输出 _fvalij 结果如下


参考资料

《深度探索C++对象模型》—— Stanley B.Lippman著,侯捷译


http://www.mrgr.cn/p/76235801

相关文章

天地图路径规划功能实现

目录 1、天地图路径规划2、路径规划3、参数说明4、Demo 1、天地图路径规划 天地图Web服务API为用户提供HTTP/HTTPS接口&#xff0c;即开发者可以通过这些接口使用各类型的地理信息数据服务&#xff0c;可以基于此开发跨平台的地理信息应用。 Web服务API对所有用户开放。使用本…

windows密码存储以及hashdump所得信息解析

1. windows登录的明文密码,存储过程是怎么样的,密文存在哪个文件下,该文件是否可以打开,并且查看到密文 在Windows中密码通常不会以明文形式存储。系统会通过保存密码的哈希值来确保安全性。 这个过程涉及到NTLM或Kerberos身份认证协议,它们负责加密存储密码。 以下是存储…

【模板】生成函数 I

多项式与形式幂级数多项式:\(A(x)=\sum\limits_{i=0}^{n}a_ix^i\)。 形式幂级数:\(A(x)=\sum\limits_{i\ge0}a_ix^i\)。形式幂级数不用考虑其收敛域。形式幂级数(多项式)的运算 设 \(A(x)=\sum\limits_{i\ge0}a_ix^i,B(x)=\sum\limits_{i\ge0}b_ix^i\)。\(A(x)+B(x)=\sum\l…

两院院士泌尿外科专家吴阶平教授

吴阶平&#xff08;1917-2011&#xff09;&#xff0c;男&#xff0c;江苏常州人&#xff0c;1933年天津汇文中学毕业&#xff0c;保送到北平燕京大学医预科&#xff0c;1937年毕业于北平燕京大学获理学士学位&#xff0c;1942年毕业于北平协和医学院获医学博士学位&#xff0c…

用 Python 开发一个【GIF表情包制作神器】

用python成为了微信斗图届的高手然后,好多人表示:虽然存了很多表情包但似乎还不是很过瘾因为它不可以自己来定制我们可不可以根据一些表情素材然后自己制作专属表情包呢像这样本来小帅b想自己实现一个表情包制作器后来发现已经有人在 GitHub 分享了 主要功能就是 可以在原有的…

云原生Kubernetes: K8S 1.29版本 部署Sonarqube

一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K8S node节点1.29.0192.168.204.10已部署Kuboard &#xff08;2&#xff09;master节点查看集群 1&…

DRM

DRM是Linux目前主流的图形显示框架,相比FB架构,DRM更能适应当前日益更新的显示硬件。 比如FB原生不支持多层合成,不支持VSYNC,不支持DMA-BUF,不支持异步更新,不支持fence机制等等,而这些功能DRM原生都支持。 同时DRM可以统一管理GPU和Display驱动,使得软件架构更为统一…

详解SDRAM基本原理以及FPGA实现读写控制

文章目录 一、SDRAM简介二、SDRAM存取结构以及原理2.1 BANK以及存储单元结构2.2 功能框图2.3 SDRAM速度等级以及容量计算 三、SDRAM操作命令3.1 禁止命令&#xff1a; 4b1xxx3.2 空操作命令&#xff1a;4b01113.3 激活命令&#xff1a;4b00113.4 读命令&#xff1a;4b01013.5 写…

Clock Switch,芯片时钟切换的毛刺是什么,如何消除

背景 芯片运行过程中需要时钟切换时,要考虑到是否会产生glitch,小小的glitch有可能导致电路运行的错误。所以时钟切换时需要特别的处理。 直接使用MUX进行时钟切换或者采用如下电路结构进行时钟切换:assign outclock = (clk1 & select) | (~select & clk0);或 assig…

【计算机网络】通过ensp实验分析二三层数据包转发过程

一、实验准备 需要提前安装好wireshark、virtalbox、WinPcap和模拟工具ensp,具体的安装过程可以自行百度~ 特别提醒一点就是virtalbox和ensp的兼容性问题,我安装的是ensp1.3.00.100版本,该版本不支持virtalbox官网的6和7版本,我这边退回到5版本才正常运行起来。二、网络拓扑…

Swagger3.0(Springdoc)日常使用记录

文章目录 前言一、默认地址二、注解OperationTag 三、SpringBoot基础配置四、Swagger导入apifox五、Swagger其他配置六 knife4j 参考文章 前言 本文并不是Swagger的使用教程&#xff0c;只是记录一下本人的操作&#xff0c;感兴趣的可以看下 一、默认地址 http://localhost:…

异或

这道题目的思路比较好 由于\(1\)到\(n\)的路径很多,我们猜想,任意选一条路径可以通过某种异或运算来得到最优解 证明:假设我们选出的路径不是最优路径,那么对于另一条最优路径,一定可以通过我们选出的路径异或上若干个简单环来达到。举个例子说明假设我们选出的是直线段\(…

rt1052点亮0.96寸spi屏

一,前言 目的是用rgb屏,但是rgb屏硬件还没准备好,所以要先学习下lvgl上位机,但是学习完要烧录到屏中看效果,所以我今天就先点亮spi屏。找了之前stm32时候点亮频的lcd驱动进行的移植,cs我不是gpio控制的,所以注释了2行,看起来无影响。 二,说明 0.96存spi驱动的LCD屏ST7…

使用Postman对@RequestPart和HttpServletRequest组合传参方式

使用Postman对RequestPart和HttpServletRequest组合传参方式 方法代码如下&#xff1a; /*** 发布*/ApiOperation("发布")ApiImplicitParams({ApiImplicitParam(name "req", value "json格式", dataType "Map", dataTypeClass Ma…

AngularJS 的生命周期和基础语法

AngularJS 的生命周期和基础语法 文章目录 AngularJS 的生命周期和基础语法1. 使用步骤2. 生命周期钩子函数3. 点击事件4. if 语句1. if 形式2. if else 形式 5. for 语句6. switch 语句7. 双向数据绑定 1. 使用步骤 // 1. 要使用哪个钩子函数&#xff0c;就先引入 import { O…

ubuntu22.04 修改内核源码教程

1. 确认当前内核版本 uname -a 2. 去ubuntu官网下载对应版本内核源码 6.5.0-28.29 : linux package : Ubuntu (launchpad.net) 3. 准备编译环境 sudo apt-get install libncurses5-dev libssl-dev build-essential openssl flex bison libelf-dev tar -xzvf linux_6.5.…

【网络通信】Windows搭建RTMP视频流服务器(含推流/拉流详细教程)

RTMP(Real-Time Messaging Protocol)是一种用于实时流媒体传输的网络协议,主要用于传输音频、视频和数据。RTMP最初是由Adobe Systems公司开发的,用于其Flash平台和Adobe Media Server,但随着技术的发展和开源社区的推动,RTMP已经成为了一个广泛使用的流媒体传输协议。今…

【计算机网络】FTP站点配置搭建教程以及相关问题解决方案(超详细)

文章目录 1、安装Window Server 20082、搭建FTP环境&#xff08;1&#xff09;安装FTP服务器&#xff08;2&#xff09;配置FTP服务器&#xff08;3&#xff09;测试FTP连接 3、遇到的问题以及解决方案&#xff08;1&#xff09;Windows无法访问此文件夹&#xff08;2&#xff…

基于直方图的图像曝光量分析FPGA实现,包含tb测试文件和MATLAB辅助验证

1.算法运行效果图预览 正常图像: checkb位于f192b和f250b之间多度曝光图像: checkb位于f192b和f250b之外,判决为曝光过度。2.算法运行软件版本 vivado2019.2matlab2022a3.算法理论概述 参考资料如下:主要采用的方法为: 4.部分核心程序`timescale 1ns / 1ps // // Compan…

人机验证 reCaptcha 无法解锁 使用 Gooreplacer 的解决方案

解决方案 浏览器搜索并安装插件 Gooreplacer(参考下方链接),新增设置:匹配模式 google.com/recaptcha 匹配类型 通配符 目标地址 recaptcha.net/recaptcha如下图:并开启,刷新页面,即可。 故障分析及解决思路 常见的人机验证(reCaptcha)网址是 google.com/recaptcha,而…