C++ 11

目录

1. 统一的列表初始化

1.1 {}初始化

1.2 std::initializer_list

2. decltype

3. 右值引用和移动语义

3.1 左值引用和右值引用

3.2 左值引用与右值引用比较

3.3 右值引用使用场景和意义

3.4 右值引用引用左值及其一些更深入的使用场景分析

3.5 完美转发

4 新的类功能


1. 统一的列表初始化

1.1 {}初始化

在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。

struct Point
{int x;int y;
};int main()
{int arr1[] = { 1, 2, 3 };int arr2[2] = { 0 };Point p = { 1, 2 };return 0;
}

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自 定义的类型使用初始化列表时,可添加等号(=),也可不添加

struct Point
{int x;int y;
};int main()
{int arr1[]{ 1, 2, 3 };int arr2[2]{ 0 };Point p{ 1, 2 };int* ptr = new int[4]{0};return 0;
}

new的对象也可以用{}初始化

class Date
{
public:Date(size_t year, size_t month, size_t day):_year(year),_month(month),_day(day){}
private:size_t _year;size_t _month;size_t _day;
};int main()
{Date d1(2024, 3, 18);Date d2 = { 2024, 3, 18 };Date d2{ 2024, 3, 18 };return 0;
}

对于自定义类型,第一个()是构造,下面两个{}是利用列表初始化。

1.2 std::initializer_list

int main()
{auto il = { 1,2,3 };cout << typeid(il).name() << endl;initializer_list<int> il2 = { 1,2,3 };return 0;
}

std::initializer_list使用场景:

std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加 std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。

也可以作为operator= 的参数,这样就可以用大括号赋值。

int main()
{auto il = { 1,2,3 };cout << typeid(il).name() << endl;initializer_list<int> il2 = { 1,2,3 };list<int> lt = { 1,2,3 };initializer_list<char> il4 = { 'a', 'b', 'c' };string s = { 'a', 'b', 'c' };string s2 = { "hello word"};initializer_list<const char*> il3 = { "hello word" , "abc"};map<int, int> m = { make_pair(1,1), make_pair(2,2) ,make_pair(3,3) };return 0;
}

对于string类型字符串类型的初始化建议还是别用,容易出bug,initializer_list<const char*>里面只有一个还行,如果大于一个就会错误,直接构造就挺好。

容器构造和赋值的实现

namespace kele
{template<class T>class vector {public:typedef T* iterator;iterator begin(){return _start;}iterator end(){return _finish;}vector(initializer_list<T> l){_start = new T[l.size()];_finish = _start + l.size();_endofstorage = _start + l.size();iterator vit = _start;for (auto e : l)*vit++ = e;}vector<T>& operator=(initializer_list<T> l) {vector<T> tmp(l);swap(_start, tmp._start);swap(_finish, tmp._finish);swap(_endofstorage, tmp._endofstorage);return *this;}private:iterator _start;iterator _finish;iterator _endofstorage;};
}int main()
{kele::vector<int> v = { 1,2,3 };for (auto e : v){cout << e << endl;}return 0;
}

2. decltype

关键字decltype将变量的类型声明为表达式指定的类型。

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)
{return x * y;
}int main()
{int x = 1;char y = 'a';decltype(x * y) z;//z intcout << typeid(z).name() << endl;double a = 0.25;decltype(multiply(a, x)) m;//m doublecout << typeid(m).name() << endl;return 0;
}


3. 右值引用和移动语义

3.1 左值引用和右值引用

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名

什么是左值?什么是左值引用?

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋 值,左值可以出现赋值符号的左边右值不能出现在赋值符号左边。定义时const修饰符后的左 值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

int main()
{// 以下的p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;// 以下几个是对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

什么是右值?什么是右值引用?

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值,匿名对象(这个不能是左值引 用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能 取地址。右值引用就是对右值的引用,给右值取别名。

int main()
{double x = 1.1, y = 2.2;// 以下几个都是常见的右值10;x + y;fmin(x, y);// 以下几个都是对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);// 这里编译会报错:error C2106: “=”: 左操作数必须为左值10 = 1;x + y = 1;fmin(x, y) = 1;return 0;
}

需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用

3.2 左值引用与右值引用比较

左值引用只能引用左值,不能引用右值。

但是const左值引用既可引用左值,也可引用右值。

右值引用只能右值,不能引用左值。

但是右值引用可以move以后的左值。

int main()
{int x = 10;int& z = x;//左值引用int&& y = 10;//右值引用int&& yy = move(x);//右值引用左值const int& xx = 10;//左值引用右值return 0;
}

3.3 右值引用使用场景和意义

左值引用的使用场景:做参数和做返回值都可以提高效率。(对于自定义类型)

string& func(const string& x)
{}

左值引用的短板:但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回, 只能传值返回。

例如: string operator+(const string& str) 

在C++98,tmp是函数内部的局部对象,所以只能拷贝构造返回值,这是一次深拷贝,不能用引用。然后s2又是一次拷贝构造,深拷贝。(编译器不优化的前提下)

这个返回值是一个临时对象,也就是右值,将亡值,这个临时对象在拷贝之后也是要析构的,可不可以利用一下这个资源呢?

右值引用和移动语义解决上述问题:

在bit::string中增加移动构造,移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。

不仅仅有移动构造,还有移动赋值

namespace kele
{class string{public:string(const char* str = "")//构造:_size(strlen(str)){cout << "构造" << endl;_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& str)//拷贝构造:_str(nullptr){cout << "string(const string & str)//拷贝构造" << endl;string tmp(str._str);swap(tmp);}string(string&& str)//移动构造:_str(nullptr),_size(0),_capacity(0){cout << "string(string&& str)//移动构造" << endl;swap(str);}string& operator=(string& str)//赋值重载{if (this != &str){cout << "string& operator=(string str)//赋值重载" << endl;string tmp(str._str);swap(tmp);return *this;}}string& operator=(string&& str)//移动赋值重载{if (this != &str){cout << "string& operator=(string&& str)//移动赋值重载" << endl;swap(str);return *this;}}void reserve(size_t n = 0){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}string& operator+=(const string& s){size_t n = s._size;if (_size + n > _capacity){reserve(_capacity + n);}strcpy(_str + _size, s._str);_size += n;return *this;}string operator+(const string& str){string tmp(_str);tmp += str;return tmp;}~string(){delete[] _str;_size = _capacity = 0;}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}private:char* _str;size_t _size;size_t _capacity;};
}

STL中的容器都是增加了移动构造和移动赋值:

3.4 右值引用引用左值及其一些更深入的使用场景分析

当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。

C++11中,std::move()函数位于头文件中,该函数名字具有迷惑性, 它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。

STL容器插入接口函数也增加了右值引用版本:

3.5 完美转发

模板中的&& 万能引用:

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值

模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是

引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值

我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{//Fun(t);Fun(forward<T>(t));完美转发
}
int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);      // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

std::forward 完美转发在传参的过程中保留对象原生类型属性

完美转发可能在真实使用场景中需要多次使用,因为右值引用在接收后都退化成了左值。


4 新的类功能

默认成员函数

原来C++类中,有6个默认成员函数:

  1.  构造函数
  2.  析构函数
  3.  拷贝构造函数
  4.  拷贝赋值重载
  5.  取地址重载
  6.  const 取地址重载

C++11 新增了两个:移动构造函数和移动赋值运算符重载。

默认移动构造生成的条件:没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个

默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造,没有实现就调用拷贝构造。

强制生成默认函数的关键字default:

Person(Person&& p) = default;

禁止生成默认函数的关键字delete:

Person(const Person& p) = delete;

继承和多态中的finaloverride关键字

在C++中,final是一个关键字,用于修饰类、成员函数或虚函数,表示它们不能被继承或重写。具体来说,final关键字有以下几个用途:

final修饰类:当一个类被声明为final时,该类不能被其他类继承。这样可以防止其他类对该类进行派生,保护该类的实现和接口不被修改。

final修饰成员函数:当一个成员函数被声明为final时,该函数不能在派生类中被重写。这样可以确保该函数的实现不会被修改。

final修饰虚函数:当一个虚函数被声明为final时,该虚函数不能在派生类中被重写。这样可以阻止派生类对该虚函数的进一步修改。

使用final关键字可以提高代码的安全性和可维护性,同时也能够更好地表达设计意图

override(重写覆盖): 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。


未完待续

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/754886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文笔记] Gradient Surgery for Multi-Task Learning

【强化学习 137】PCGrad - 知乎 多任务学习(multi task):任务权重、loss均衡、梯度下降那点事 - 知乎 ICLR 2020 rejected submission:Yu T, Kumar S, Gupta A, et al. Gradient surgery for multi-task learning[J]. arXiv preprint arXiv:2001.06782, 2020. mul…

Java基础经典10道题

目录 for循环的嵌套 题目一: 求101到200之间的素数的个数,并打印 代码分析: 注意点: 题目二:开发验证码 代码分析: 题目三:数组元素的复制 代码分析: 题目四:评委打分 健壮版代码: 代码分析:看源码 注意点: 题目五:数字加密 优化版代码: 代码分析: 题目六:数字…

SpringCloud Sleuth 分布式请求链路跟踪

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十篇&#xff0c;即介绍 Sleuth 分布式请求链路跟踪。 二、概述 2.1 出现的原因 在微服务框架中&…

万界星空科技WMS仓储管理包含哪些具体内容?

wms仓库管理是通过入库业务、出库业务、仓库调拨、库存调拨和虚仓管理等功能&#xff0c;综合批次管理、物料对应、库存盘点、质检管理、虚仓管理和即时库存管理等功能综合运用的管理系统&#xff0c;有效控制并跟踪仓库业务的物流和成本管理全过程&#xff0c;实现完善的企业仓…

从WAF到WAAP的研究

对于需要保护Web应用程序和API的企业来说&#xff0c;从WAF到WAAP的转变已成为一种必然趋势。采用WAAP平台可以更为全面和高效地保护Web应用程序和API的安全&#xff0c;同时避免了高昂的维护成本和攻击绕过WAF的风险。 网络安全领域的发展趋势是从WAF到WAAP的转变。WAF作为传…

如何利用IP地址分析风险和保障网络安全

随着网络攻击的不断增加和演变&#xff0c;保障网络安全已经成为了企业和组织不可忽视的重要任务。在这样的背景下&#xff0c;利用IP地址分析风险和建立IP风险画像标签成为了一种有效的手段。本文将深入探讨IP风险画像标签的作用以及如何利用它来保障网络安全。 IP风险画像查…

一键制作iOS上架App Store描述文件教程

摘要 本篇博文详细介绍了在iOS上架过程中所需的基础项目&#xff0c;包括IOS生产环境证书、APPID包名制作以及APP的描述文件。通过使用appuploader进行证书制作和上传IPA到App Store&#xff0c;能够快速掌握真机测试和上架流程。 引言 在iOS应用开发过程中&#xff0c;正确…

PHP反序列化--引用

一、引用的理解&#xff1a; 引用就是给予一个变量一个恒定的别名。 int a 10; int b &a; a 20; cout<<a<<b<<endl; 输出结果 : a20、b20 二、靶场复现&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); include("flag.p…

android 顺滑滑动嵌套布局

1. 背景 最近项目中用到了上面的布局&#xff0c;于是使用了scrollviewrecycleview&#xff0c;为了自适应高度&#xff0c;重写了recycleview&#xff0c;实现了高度自适应&#xff1a; public class CustomRecyclerView extends RecyclerView {public CustomRecyclerView(Non…

【HTTP】面试题整理

HTTP&#xff1a;什么是队头阻塞以及怎么解决&#xff1f; 队头阻塞&#xff08;Head-of-Line Blocking&#xff09; 计算机网络中的一个概念&#xff0c;特别是在处理HTTP请求时。当多个HTTP请求被发送到一个服务器&#xff0c;并且这些请求被放置在一个队列中等待处理时&…

iview 不请求接口修改table本地数据 不刷新的本质问题以及最简单的解决方法

在日常的开发中&#xff0c;相信大家都遇到过这样的问题&#xff0c;通过请求接口&#xff0c;而后赋值table数据&#xff0c;页面都是正常的刷新渲染的&#xff0c;但是有时&#xff0c;不需要请求接口&#xff0c;只修改本地的固定数据的话&#xff0c;页面的table表格数据却…

【每日力扣】 修剪二叉搜索树与复原 IP 地址

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害。 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&am…

Git 仓库瘦身与 LFS 大文件存储

熟悉 Git 的小伙伴应该都知道随着 Git 仓库维护的时间越来越久&#xff0c;追踪的文件越来越多&#xff0c;git 存储的 objects 数量会极其庞大&#xff0c;每次从远程仓库 git clone 的时候都会墨迹很久。如果我们不小心 git add 了一个体积很大的文件&#xff0c;且 git push…

Linux系统(四)- 进程初识 | 环境变量 | 进程地址空间

~~~~ 前言冯诺依曼体系结构&#xff08;重要&#xff09;总览CPU工作方式什么是指令集&#xff1f;CPU为什么只和内存打交道&#xff08;数据交换&#xff09;&#xff1f;木桶效应&#xff1a;在数据层面的结论程序运行为什么要加载到内存&#xff1f; 进一步理解计算机体系结…

MySQL—数据库导入篇

什么是数据库&#xff1f; 数据库是干啥的&#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库。 MySQL属于哪一类数据库&#xff1f; MySQL是一种关系型数据库。所谓的关系型数据库&#xff0c;是建立在关系模型基础上的数据库&a…

Cesium:绘制一个 3DTiles 对象的外包盒顶点

作者:CSDN @ _乐多_ 本文将介绍如何使用 Cesium 引擎根据模型的中心坐标,半轴信息,绘制一个 3DTiles 对象的外包盒顶点。 外包盒是一个定向包围盒(Oriented Bounding Box),它由一个中心点(center)和一个包含半轴(halfAxes)组成。半轴由一个3x3的矩阵表示,这个矩阵…

Java安全基础 关键概念过关

Java安全基础 关键概念汇总 文章目录 Java安全基础 关键概念汇总前置知识1.构造器this以及包的使用2.继承3.重写/ 重载 / super4.多态5.区分和equals方法6.toString的使用7.Object的概念8.static,final,代码块static代码块final 9.动态代理10.类的动态加载1)类加载器含义&#…

卷积篇 | YOLOv8改进之C2f模块融合SCConv | 即插即用的空间和通道维度重构卷积

前言:Hello大家好,我是小哥谈。SCConv是一种用于减少特征冗余的卷积神经网络模块。相对于其他流行的SOTA方法,SCConv可以以更低的计算成本获得更高的准确率。它通过在空间和通道维度上进行重构,从而减少了特征图中的冗余信息。这种模块的设计可以提高卷积神经网络的性能。本…

如何正确从github上下载数据集等内容

文章目录 一、现象&#xff1a;二、解决方案 一、现象&#xff1a; 数据集点击下载没有反应&#xff0c;那需要怎么下载数据集呢&#xff1f; 二、解决方案 输入以下命名行&#xff0c;亲测有效 git clone https://github.com/mymusise/ChatGLM-Tuning.git

【ADF4351】使用FPGA进行SPI寄存器配置、使用FPGA计算各个频率的频点,ADF4351配置程序

简介 特性 输出频率范围&#xff1a;35 MHz至4,400 MHz 小数N分频频率合成器和整数N分频频率合成器 具有低相位噪声的VCO 可编程的1/2/4/8/16/32/64分频输出 典型抖动&#xff1a;0.3 ps rms EVM(典型值&#xff0c;2.1 GHz)&#xff1a; 0.4% 电源&#xff1a;3.0 V至3.6 V …