C++进阶--C++11(1)

C++11是C++编程语言的一个版本,于2011年发布。C++11引入了许多新特性,为C++语言提供了更强大和更现代化的编程能力。这篇文章将对C++11的一些新增特性进行讲解和实际应用场景。

统一的列表初始化

{}初始化

在C++98中,使用{}符号的一般只仅限于对数组和结构体元素的初始化;
在C++11中,引入了使用大括号{}进行初始化的列表初始化(又称为统一初始化语法)。这种初始化方式用于各种情况下的对象初始化,包括变量、数组、结构体、类等。

struct Point
{int _x;int _y;
};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()
{//C++98就支持的初始化(数组和结构体)int arr1[] = { 1,2,3,4 };int arr2[]{ 1,2,3,4 };Point p{ 1,2 };//oldDate d1(2024, 03, 21);//newDate d2 = { 2024,03,21 };Date d3{ 2024,03,21 };//使用初始化列表时,加不加等于号'='没有区别
}

使用{}进行初始化有以下几个优点:

  • 统一性:无论是内置类型还是自定义类型,都可以使用同样的方式进行初始化,提高了代码的一致性和可读性。

  • 防止窄化转换(narrowing conversion):在{}初始化中,如果存在可能导致数据丢失的窄化转换(比如将浮点数转换为整数),编译器会报错,避免了潜在的问题。

  • 初始化列表的支持:{}初始化还可以用于初始化列表,可以方便地一次性初始化多个元素,比如数组或结构体的成员。

std::initializer_list

std::initializer_list是C++11引入的一种特殊的容器,用于表示初始化列表。它允许以大括号{}的形式初始化一组值,并将其作为参数传递给函数或构造函数

使用std::initializer_list,可以方便地传递不确定数量的参数,并以统一的方式进行处理。它的语法类似于标准库容器(如vector、list等),可以使用迭代器等操作进行访问和处理。

在这里插入图片描述

下面是一个简单的示例,展示了如何使用std::initializer_list:

void printValues(std::initializer_list<int> values) {for (auto value : values) {cout << value << " ";}cout << endl;
}int main() {printValues({1, 2, 3, 4, 5}); // 使用初始化列表调用函数return 0;
}

在上述示例中,printValues函数接受一个std::initializer_list类型的参数,并使用for循环打印每个值。在main函数中,我们使用初始化列表{1, 2, 3, 4, 5}调用了printValues函数。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

decltype

decltype是C++11引入的一个关键字,用于获取表达式的类型它可以在编译时推导出表达式的类型,并将其作为decltype表达式的返回值

在这里插入图片描述

template<class T1, class T2>
void F(T1 t1, T2 t2)
{decltype(t1 * t2) ret;cout << typeid(ret).name() << endl;
}
int main()
{const int x = 1;const double y = 2.2;decltype(x*y) ret; // ret的类型是doubledecltype(&x) p; // p的类型是int*cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;F(1, 'a');return 0;
}

在这里插入图片描述
在这里插入图片描述

右值引用

什么是左值和左值引用?

左值是一个表示数据的表达式,我们可以获取它的地址,左值由此定义出现在赋值号的左边;
左值引用就是对左值的引用。

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;
}

左值总结

int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}

右值总结

int main()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}

在这里插入图片描述

应用场景

namespace fnc
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){cout << "string(char* str)" << endl;_str = new char[_capacity + 1];strcpy(_str, str);}// s1.swap(s2)void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 深拷贝" << endl;string tmp(s._str);swap(tmp);}// 赋值重载string& operator=(const string& s){cout << "string& operator=(string s) -- 深拷贝" << endl;string tmp(s);swap(tmp);return *this;}// 移动构造string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 移动语义" << endl;swap(s);}// 移动赋值string& operator=(string&& s){cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;}~string(){delete[] _str;_str = nullptr;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size >= _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}//string operator+=(char ch)string& operator+=(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}private:char* _str;size_t _size;size_t _capacity; // 不包含最后做标识的\0};string to_string(int value){bool flag = true;if (value < 0){flag = false;value = 0 - value;}string str;while (value > 0){int x = value % 10;value /= 10;str += ('0' + x);}if (flag == false){str += '-';}std::reverse(str.begin(), str.end());return str;}}
void func1(fnc::string s)
{}
void func2(const fnc::string& s)
{}
int main()
{fnc::string s1("hello world");// func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值func1(s1);func2(s1);string operator+=(char ch) 传值返回存在深拷贝string& operator+=(char ch) 传左值引用没有拷贝提高了效率s1 += '!';fnc::string ret1 = fnc::to_string(1234);//默认构造+拷贝构造+拷贝构造->默认构造fnc::string ret2;//默认构造ret2 = fnc::to_string(1234);//默认构造+拷贝构造+赋值构造->默认构造+移动赋值fnc::string ret3(move(ret2));//将ret2强制转换为右值,这样就使用了移动构造,但这样会导致ret2是空的了;for (auto a : ret2){cout << a << endl;}return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

链表移动构造的应用场景

链表链接入口
在这里插入图片描述
在这里插入图片描述

int main()
{fnc::list<fnc::string> lt;fnc::string s1("1111");lt.push_back(s1);cout << "-----" << endl;lt.push_back(fnc::string("2222"));cout << "-----" << endl;lt.push_back("2222");cout << "-----" << endl;return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完美转发

完美转发是一种编程技巧,主要用于在泛型函数中保留参数的类型和值类别(左值或右值),以便更高效准确地传递参数。通过使用右值引用和模板类型推导,完美转发允许我们在函数中以原始参数的形式将参数传递给其他函数,避免不必要的拷贝操作,提高性能

为了实现完美转发,通常会使用std::forward函数。std::forward被称为完美转发的原因是它能保持原始参数的值属性不变。也就是说,如果原始参数是左值,经过std::forward处理后该参数还是左值;如果原始参数是右值,经过std::forward处理后它还是右值。

在C++11中,完美转发与万能引用(Universal Reference)紧密相关。使用T&&类型的形参既可以绑定右值,又可以绑定左值。但需要注意的是,只有在发生类型推导时,T&&才表示万能引用;否则表示右值引用。

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(std::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;
}

在这里插入图片描述
在这里插入图片描述

新的类功能

在这里插入图片描述

//移动构造函数
class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p):_name(p._name),_age(p._age){cout << "Person(const Person& p):拷贝构造" << endl;}/*Person& operator=(const Person& p){if (this != &p){_name = p._name;_age = p._age;}cout << "Person& operator=(const Person& p) 赋值重载" << endl;return *this;}*//*~Person(){}*/private:fnc::string _name;int _age;
};int main()
{Person s1("haha",1);cout << "-----" << endl;Person s2(s1);//拷贝构造cout << "-----" << endl;Person s3;s3 = s1;//赋值cout << "-----" << endl;Person s4=move(s1);//移动构造cout << "-----" << endl;Person s5;s5 = move(s2);}

在这里插入图片描述
在这里插入图片描述

default

C++中的default是一个关键字,它在类特殊成员函数中的作用是指示编译器生成默认的实现

在C++11标准之前,当程序员不显示定义类的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符等特殊成员函数时,编译器会自动为其生成一个默认的实现。而在C++11标准引入了default关键字后,程序员可以使用"default"来显式地指示编译器生成默认的实现,避免显式的定义空实现。

比如,在以下情况下可以使用"default":

  1. 默认构造函数:如果类没有定义任何构造函数,可以使用"default"来指示编译器生成默认的构造函数。
class MyClass {
public:MyClass() = default;
};
  1. 默认析构函数:如果类不需要进行特殊的资源管理,可以使用"default"来指示编译器生成默认的析构函数。
class MyClass {
public:~MyClass() = default;
};
  1. 默认拷贝构造函数和拷贝赋值运算符:当类的成员变量都可以按照默认的方式进行拷贝,可以使用"default"来指示编译器生成默认的拷贝构造函数和拷贝赋值运算符。
class MyClass {
public:MyClass(const MyClass&) = default;MyClass& operator=(const MyClass&) = default;
};

需要注意的是,使用"default"关键字生成默认函数时,编译器会根据类的成员变量来决定是否生成合适的实现。如果类中存在不能被默认实现的成员变量,那么编译器将无法生成默认函数,此时需要显式地定义相应的特殊成员函数。

delete

在C++中,delete是一个关键字,用于删除特殊成员函数或阻止某些函数的使用

  1. 删除特殊成员函数:通过在类定义中声明特殊成员函数,并在后面加上= delete;来删除该函数的默认生成。例如:
class MyClass {
public:MyClass() = delete; // 删除默认构造函数MyClass(const MyClass&) = delete; // 删除拷贝构造函数MyClass& operator=(const MyClass&) = delete; // 删除拷贝赋值运算符
};

这样一来,当程序尝试使用删除的函数时,编译器将会报错。

  1. 阻止函数的使用:通过在函数声明后面加上= delete;表示删除该函数的定义,阻止程序使用该函数。例如:
void foo(int) = delete; // 阻止使用int型参数的foo函数
void bar() = delete; // 阻止使用无参数的bar函数

这样一来,如果程序尝试调用被删除的函数,编译器将会报错。

通过使用delete关键字,可以更好地控制特殊成员函数的生成和禁止某些函数的使用,提高代码的可读性和安全性。

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

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

相关文章

基于蚁群算法的三维路径规划(matlab实现)

作品简介 1 理论基础 1.1 三维路径规划问题概述 三维路径规划指在已知三维地图中&#xff0c;规划出一条从出发点到目标点满足某项指标最优&#xff0c;并且避开了所有三维障碍物的三维最优路径。现有的路径规划算法中&#xff0c;大部分算法是在二维规划平面或准二维规划平面…

今日头条signature参数js逆向(爬虫)

今日头条是ajax动态加载 话不多说&#xff0c;直接上代码 windowglobal;window.location{"ancestorOrigins": {},"href": "https://www.toutiao.com/","origin": "https://www.toutiao.com","protocol": "…

连接Redis不支持集群错误,ERR This instance has cluster support disabled,解决方案

1. 问题背景 调整redis的配置后&#xff0c;启动程序时&#xff0c; 会报如下错误&#xff1a; [redis://172.16.0.8xxx]: ERR This instance has cluster support disabledSuppressed: io.lettuce.core.RedisCommandExecutionException: ERR This instance has cluster supp…

【C++】二分查找算法(模板)

重点 只需要记住两点&#xff1a; 1.left right 时&#xff0c;一定就是最终结果&#xff08;包括找不到目标值&#xff09;&#xff0c;无需再次判断&#xff0c;如果判断就会死循环 2.求中点如果是求左端点 mid left (right - left)/2 如果是求右端点 mid left (right -…

MATLAB 自定义均值滤波 (53)

MATLAB 自定义均值滤波 (53) 一、算法介绍二、算法实现1.原理2.代码一、算法介绍 均值滤波,是一种常见的点云平滑算法,改善原始点云的数据质量问题,MATLAB自带的工具似乎不太友好,这里提供自定义实现的点云均值滤波算法,具体效果如下所示: 均值滤波前: 均值滤波后:…

计算机网络 - 基础篇总结

TCP/IP 网络模型有哪几层&#xff1f; 1.应用层 为用户提供应用功能 2.传输层 负责为应用层提供网络支持 使用TCP和UDP 当传输层的数据包大小超过 MSS&#xff08;TCP 最大报文段长度&#xff09; &#xff0c;就要将数据包分块&#xff0c;这样即使中途有一个分块丢失或损坏…

算法学习——LeetCode力扣图论篇2(1020. 飞地的数量、130. 被围绕的区域、827. 最大人工岛)

算法学习——LeetCode力扣图论篇2 1020. 飞地的数量 1020. 飞地的数量 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个大小为 m x n 的二进制矩阵 grid &#xff0c;其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相…

【linux】lsof命令使用

1. 功能 lsof list open files, 列出被进程所使用的文件名称。 2. 基础语法 3. 参数含义 参数含义-a过滤出多个选项要同时满足的文件-U仅列出UNIX-like系统的socket文件类型。-u指定用户&#xff0c;比如-u atiaisi&#xff0c;会把用户atiaisi相关的进程使用的文件列出来。…

游戏运营分析:如何在新游戏上线初期实现精细化运营?

一、背景介绍 在当今的手游市场中&#xff0c;每一款新游戏的发布都如同踏上一段充满未知与挑战的探险之旅。游戏刚上线时&#xff0c;运营情况往往如同飘摇的小船&#xff0c;随时可能受到风浪的侵袭。此时&#xff0c;如何准确地找到问题所在&#xff0c;为游戏的健康运营和持…

SAD法(附python实现)和Siamese神经网络计算图像的视差图

1 视差图 视差图&#xff1a;以左视图视差图为例&#xff0c;在像素位置p的视差值等于该像素在右图上的匹配点的列坐标减去其在左图上的列坐标 视差图和深度图&#xff1a; z f b d z \frac{fb}{d} zdfb​ 其中 d d d 是视差&#xff0c; f f f 是焦距&#xff0c; b b…

openGauss学习笔记-254 openGauss性能调优-使用Plan Hint进行调优-子链接块名的hint

文章目录 openGauss学习笔记-254 openGauss性能调优-使用Plan Hint进行调优-子链接块名的hint254.1 功能描述254.2 语法格式254.3 参数说明254.4 示例 openGauss学习笔记-254 openGauss性能调优-使用Plan Hint进行调优-子链接块名的hint 254.1 功能描述 指明子链接块的名称。…

《书生·浦语大模型全链路开源开放体系》学习笔记

书生浦语大模型全链路开源开放体系-学习笔记 大模型成为发展通用人工智能的重要途径专用模型通用大模型 书生大模型开源历程InternLM2回归语言建模的本质主要亮点性能全方位提升强大的内生计算能力 从模型到应用典型流程全链条开源开放体系数据数据集获取预训练微调XTuner 评测…

【Go】四、包名、访问范围控制、标识符、运算符

文章目录 1、_2、包名3、命名大小影响可访问范围4、运算符5、获取终端输入 1、_ 下划线"_"本身在Go中是一个特殊的标识符&#xff0c;称为空标识符用于忽略某个值 1&#xff09;忽略导入的没使用的包 2&#xff09;忽略某个返回值 2、包名 main包是程序的入口包&a…

vulnhub pWnOS v2.0通关

知识点总结&#xff1a; 1.通过模块来寻找漏洞 2.msf查找漏洞 3.通过网站源代码&#xff0c;查看模块信息 环境准备 攻击机&#xff1a;kali2023 靶机&#xff1a;pWnOS v2.0 安装地址&#xff1a;pWnOS: 2.0 (Pre-Release) ~ VulnHub 在安装网址中看到&#xff0c;该靶…

IDEA无法连接虚拟机中的Redis的解决方案,无法连接Jedis,无法ping通虚拟机的解决方案

首先&#xff0c;笔者先说明一下自身的情况&#xff0c;怎么连接都连不上&#xff0c;网上的教程全部都看了一遍&#xff0c;基本上没用得上的&#xff0c;这篇文章里面的解决方案包括了笔者能在网上找到了最全面的办法总结&#xff0c;最后终于是连上了 目录 一.连接Jedis出错…

.Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置

.Net Core/.Net6/.Net8 &#xff0c;启动配置/Program.cs 配置 没有废话&#xff0c;直接上代码调用 没有废话&#xff0c;直接上代码 /// <summary>/// 启动类/// </summary>public static class Mains{static IServiceCollection _services;static IMvcBuilder _…

适用于汽车导航系统的车载晶振FC-13A

用于汽车导航系统的32,768KHz耐高温车载晶振FC-13A。其实FC-13A这款车载晶振还是有很多特点的&#xff0c;FC-13A是一款尺寸为3215的32,768KHz耐高温晶振&#xff0c;FC-13A符合AEC-0200被动元件汽车级品质标准认证&#xff0c;是FC-135车载晶振设备用升级版&#xff0c;区别主…

【机器学习】数据探索(Data Exploration)---数据质量和数据特征分析

一、引言 在机器学习项目中&#xff0c;数据探索是至关重要的一步。它不仅是模型构建的基础&#xff0c;还是确保模型性能稳定、预测准确的关键。数据探索的过程中&#xff0c;数据质量和数据特征分析占据了核心地位。数据质量直接关系到模型能否从数据中提取有效信息&#xff…

【排序算法——数据结构】

文章目录 排序排序的基本概念1.插入排序2.希尔排序3.冒泡排序4.快速排序5.简单排序6.堆排序7.归并排序8.基数排序8.外部排序9.败者树10.置换选择排序 排序 排序的基本概念 排序&#xff0c;就是重新排列表中的元素&#xff0c;使表中的元素满足按关键字有序的过程 评价指标算…

Git 如何合并多个连续的提交

我平常的编程喜欢是写一段代码就提交一次&#xff0c;本地一般不攒代码&#xff0c;生怕本地有什么闪失导致白干。但这样就又导致一个问题&#xff1a;查看历史日志时十分不方便&#xff0c;随便找一段提交可以看到&#xff1a; > git log --oneline 8f06be5 add 12/qemu-h…