当前位置: 首页 > news >正文

C++学习笔记(1):在默认构造函数内部使用带参数的构造函数

题目

以下代码的输出是不是0:

#include <unordered_map>
#include <iostream>using namespace std;struct CLS{int i;CLS(int i_) :i(i_){}CLS(){CLS(0);}
};int main(){CLS obj;std::cout << obj.i << endl;return 0;
}

结果

-858993460

为什么呢?

定义对象的流程

以下内容参考自:从一道题谈C++中构造函数调用构造函数 - 中土 - 博客园 (cnblogs.com)

  • 代码奇怪的地方在于构造函数中调用了自己的另一个构造函数,我们知道,当定义一个对象时,会按顺序做2件事情:

1)分配好内存(非静态数据成员是未初始化的)

2)调用构造函数(构造函数的本意就是初始化非静态数据成员)

  • 显然上面代码中,CLS obj;这里已经为obj分配了内存,然后调用默认构造函数,但是默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时CLS对象,它调用CLS(int)构造函数,将这个匿名临时对象自己的数据成员m_i初始化为0;但是obj的数据成员并没有得到初始化。于是obj的m_i是未初始化的,因此其值也是不确定的

  • 验证:在析构函数中打印一个destroy,结果如下,可见生成了两个对象。

~CLS(){cout << "destroy" << endl;}destroy
-858993460
destroy

  • 从这里,我们归纳如下:

  1. 在c++里,由于构造函数允许有默认参数,使得这种构造函数调用构造函数来重用代码的需求大为减少

  1. 如果仅仅为了一个构造函数重用另一个构造函数的代码,那么完全可以把构造函数中的公共部分抽取出来定义一个成员函数(推荐为private),然后在每个需要这个代码的构造函数中调用该函数即可

解决方案:placement new

最好的方法当然是不调用,但偶尔我们还是希望在类的构造函数里调用另一个构造函数,可以按下面方式做:

在构造函数里调用另一个构造函数的关键是让第二个构造函数在第一次分配好的内存上执行,而不是分配新的内存,这个可以用标准库的placement new做到

inline void *__cdecl operator new(size_t, void *_P)
{return (_P); 
} 

placement new即为定位new,当需要在制定内存而不是新开辟一个内存构建新对象时,就使用之

  • 格式:

  • address:placement new所指定的内存地址

  • ClassConstruct:对象的构造函数

Object * p = new (address) ClassConstruct(...);

于是代码修改为:

#include <unordered_map>
#include <iostream>using namespace std;struct CLS{int i;CLS(int i_) :i(i_){}CLS(){new (this)CLS(0);} // 使用placement new
};int main(){CLS obj;std::cout << obj.i << endl;return 0;
}

这时的输出就是0了:

0
destroy
http://www.lryc.cn/news/17692.html

相关文章:

  • Android面试题_安卓面经(23/30)设计模式源码案例
  • Dubbo性能调优参数以及原理
  • vue3全家桶之vuex和pinia持久化存储基础(二)
  • LAMP架构与搭建论坛
  • 代码随想录 || 回溯算法93 78 90
  • 界面组件Kendo UI for Angular——让网格数据信息显示更全面
  • 【Linux】进程状态|优先级|进程切换|环境变量
  • 合宙Air780E|FTP|内网穿透|命令测试|LuatOS-SOC接口|官方demo|学习(18):FTP命令及应用
  • 大规模 IoT 边缘容器集群管理的几种架构-4-Kubeedge
  • Spring底层核心原理解析
  • OpenStack手动分布式部署Glance【Queens版】
  • 谈一谈你对View的认识和View的工作流程
  • Redis集群的脑裂问题
  • 互斥信号+任务临界创建+任务锁
  • Elasticsearch7.8.0版本进阶——文档搜索
  • spring security权限问题
  • mysql 8.0.22安装
  • Mysql系列:Mysql5.7编译安装
  • 设备树(配合LED驱动说明)
  • (二十六)大白话如何从底层原理解决生产的Too many connections故障?
  • ASEMI高压MOS管60R380参数,60R380特征,60R380应用
  • Python期末试卷
  • Linux | 网络通信 | http协议介绍 | cookie策略讲解
  • 招投标系统简介 招投标系统源码 java招投标系统 招投标系统功能设计
  • winapi获取和修改camera raw界面元素数据
  • C++问答汇总_2023自用
  • IDA 实战--(2)熟悉工具
  • Deep Unsupervised Learning using Nonequilibrium Thermodynamics论文翻译学习
  • 使用Autoware标定工具包联合标定相机和激光雷达
  • 了解线程安全