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

【C++】c++ 11

目录

前言

列表初始化

std::initializer_list

右值引用和移动拷贝

左值和右值

左值引用和右值引用的区别

万能引用(引用折叠)

完美转发

默认成员函数控制


列表初始化

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

//也算是兼容C
struct Point
{int _x;int _y;
};
int main()
{int array1[] = { 1, 2, 3, 4, 5 };int array2[5] = { 0 };Point p = { 1, 2 };return 0;
}

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

struct Point
{int _x;int _y;
};
int main()
{int x1 = 1;int x2{ 2 };int array1[]{ 1, 2, 3, 4, 5 };int array2[5]{ 0 };Point p{ 1, 2 };// C++11中列表初始化也可以适用于new表达式中int* pa = new int[4] { 0 };return 0;
}

创建对象时也可以使用列表初始化方式调用构造函数初始化:

class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2022, 1, 1); // old style// C++11支持的列表初始化,下面两个会调用构造函数初始化Date d2{ 2022, 1, 2 };Date d3 = { 2022, 1, 3 };return 0;
}
std::initializer_list

initializer_list是C++11新增加的容器,底层就是一个数组。

int main()
{//这里初始化其实是构造初始化,先不在意底层initializer_list<int> l = {0, 1, 2, 34};initializer_list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl;
}

initializer_list平常并无作用,但是C++11对{}有特殊处理,它真正的应用场景是用于构造其它容器

//C++11为vector、map等容器都提供了initializer_list做参数的构造
//原理也很简单,先将{}转变成initializer_list,然后遍历initializer_list尾插即可
int main()
{vector<int> v = { 0, 1, 2, 3, 4, 5 };for (auto e : v) cout << e << " ";cout << endl;map<int, int> m = { {0, 1}, {1, 0}, {10, 9} };for (auto kv : m){cout << kv.first << ":" << kv.second << endl;}cout << endl;
}

右值引用和移动拷贝

左值和右值

首先先分清什么是左值,什么是右值——不是在=左边的就叫左值,在=右边的就叫右值

左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。

最显著的特点就是左值可以被取地址,右值不能被取地址(是否真的存储)

左值引用就是给左值的引用,给左值取别名。

// 以下的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;

右值不能被取地址,例如字面常量、表达式返回值,函数返回值(左值引用返回不是右值,传值返回才是右值)

右值引用就是对右值的引用,给右值取别名

// 以下几个都是常见的右值
10;
x + y;
fmin(x, y);
// 以下几个都是对右值的右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);

左值引用和右值引用的区别

1.左值引用只能引用左值,不能引用右值;右值引用同理

2.const 左值引用可以引用左值也可以引用右值,但是反过来就不行

3.右值引用可以引用move后的左值

左值引用的使用场景: 做参数和做返回值都可以提高效率

为什么要有右值引用呢,主要是为了弥补左值引用的不足

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

例如:zzb::string to_string(int value)函数中可以看到,这里只能使用传值返回,传引用返回当该函数栈帧被销毁的时候该位置有可能被其他变量所占用,存在很大的问题,但是传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造),效率很低

zzb::string to_string(int x){bit::string ret;while (x){int val = x % 10;x /= 10;ret += ('0' + val);}

内置类型的右值叫做纯右值,将自定义的右值称为将亡值

我们先来看下面这两种情况

int main()
{bit::string s1 = bit::to_string(1234);bit::string s2;s2 = bit::to_string(2345);return 0;
}

下面的那个:

str拷贝给临时对象,临时对象拷贝构造给ret2

自定义创建时调用一次构造函数

函数栈帧销毁的时候,创建临时对象的时候调用拷贝构造

返回值作为右值给左值赋值的时候又调用拷贝构造

 上面的减少的一次可以理解为没有产生临时对象了,直接赋值给ret2,这时编译器优化后的结果

老一点的编译器可能没有这样优化

如果是浅拷贝的类那还没事,但如果是深拷贝的类,短短一个赋值操作就要深拷贝三次,代价太大了,反正这个函数栈帧里的空间都要被销毁的,如果把它拿过来直接用的话,是不是就很方便了

所以就有了移动构造和移动赋值,这时候右值引用的价值就体现出来了,可以区分左值和右值了

如果参数传的是将亡值,则直接将资源交换,不仅减少了拷贝,还将不要的资源转移到了即将要销毁的空间,过后自动销毁,一举两得

移动构造——不用开辟空间,直接交换得到目标值,目标即将被销毁的时候使用

右值引用是间接起作用的,对深拷贝的类有意义

左值引用是直接起作用,传引用返回

右值被右值引用后的属性是左值

右值不能修改,但是被右值引用之后需要被修改——>属性变成左值(不能修改怎么转移资源,也就无法实现移动构造和移动拷贝)

万能引用(引用折叠)

函数模板下才有用!

 可以接受左值和右值,左值的时候就相当于将两个&折叠成一个,所以也叫引用折叠

完美转发

按照上面的写法写即可

可以保持原有属性(右值被右值引用后属性变成左值)

默认成员函数控制

这里为什么条件那么严格呢?

其实这三个一般都是绑定在一起的,因为写了析构一般都设计深拷贝,所以也就要自己写拷贝构造和拷贝赋值,不然会出现问题

http://www.lryc.cn/news/439086.html

相关文章:

  • uni-app 应用名称 跟随系统语言 改变
  • 【大模型实战篇】高质量数据过滤及一种BoostedBaggingFilter处理方法的介绍
  • 使用Python和Proxy302代理IP高效采集Bing图片
  • Python酷库之旅-第三方库Pandas(118)
  • 讨论人机交互研究中大语言模型的整合与伦理问题
  • OpenCV结构分析与形状描述符(23)确定一个点是否位于多边形内的函数pointPolygonTest()的使用
  • GitLab CI_CD 从入门到实战笔记
  • 微服务实战系列之玩转Docker(十五)
  • 本地调试spark,访问kerberos鉴权的hdfs、hive
  • Ubuntu 安装包下载(以20版本 阿里镜像站为例子)
  • 会声会影Corel VideoStudio2025旗舰版最新中文旗舰版新功能讲解及使用会声会影使用教程
  • 【人工智能】OpenAI发布GPT-o1模型:推理能力的革命性突破,这将再次刷新编程领域的格局!
  • 2024年TCGA基因表达数据下载(最新版)
  • 1. 运动控制指令概要(omron 机器自动化控制器)
  • 依赖注入(Dependency Injection)
  • PHP环境搭建
  • 小叶OJ 2716: 过河问题 ← 贪心算法
  • LeetCode509:斐波那契数列
  • 5G前传-介绍
  • 【Python机器学习】循环神经网络(RNN)——超参数
  • 【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树
  • Node.js的学习2——内置模块(一)
  • 信息安全工程师(5)域名与域名解析
  • idear导入他人项目如何快速运行
  • 直流无刷电机霍尔线序自学习解释
  • C++学习笔记(26)
  • 安卓14剖析SystemUI的ShadeLogger/LogBuffer日志动态控制输出dumpsy机制
  • 华为CNA VRM搭建(使用vmware worfstartion搭建)
  • 【WRF工具】WRF Domain Wizard第二期:使用教程
  • 智能摄像头MP4格式化恢复方法