【C++复习】C++11经典语法

文章目录

  • {}列表初始化
      • 1. 初始化内置类型变量
      • 2. 初始化数组
      • 3. 初始化标准容器
      • 4. 初始化自定义类型
      • 5. 构造函数初始化列表
      • 6. 初始化列表(initializer_list)
      • 7. 返回值初始化
      • 8. 静态成员变量和全局变量的就地初始化
      • 9. 防止类型收窄
      • 总结
  • decltype
  • 右值引用
  • 完美转发--由右值引用引发的问题
  • delete default
  • 逗号表达式
      • 特性
      • 示例
      • 注意事项
  • 可变参数模板
    • 展开参数包
  • emplace_back
  • 仿函数
  • function包装器/适配器/类模板
  • bind函数模板/包装器/适配器

{}列表初始化

1. 初始化内置类型变量

  • 直接初始化int a{10};。明确表达初始化过程,避免与赋值混淆。
  • 空列表初始化:如果{}内为空,则内置类型变量会被初始化为该类型的零值,如int b{};会将b初始化为0

2. 初始化数组

  • C++98风格:在C++98中,数组初始化就需要使用{},如int arr1[] = {1, 2, 3};
  • C++11风格:C++11引入了更简洁的数组初始化方式,允许省略=,如int arr2[]{1, 2, 3};

3. 初始化标准容器

  • STL容器:如vectormap等,可以使用{}进行初始化,

    vector<int> v{1, 2, 3};
    map<int, float> m{ {1, 1.0f}, {2, 2.0f} };
    

4. 初始化自定义类型

  • 无模板类:对于自定义的无模板类,可以在构造函数中使用{}初始化成员变量,也可以在对象创建时直接使用{}进行初始化,如struct A { A(int a = 0, int b = 0) : _a(a), _b(b) {} }; A a{1, 2};
  • 模板类:模板类同样支持使用{}进行初始化,如template<class T> struct B { B(T c = 0, T d = 0) : _c(c), _d(d) {} }; B<int> b{3, 4};

5. 构造函数初始化列表

  • 在类的构造函数中,可以使用{}来初始化成员变量,这有助于确保成员变量在构造函数体执行之前就被正确初始化。

6. 初始化列表(initializer_list)

  • C++11引入了initializer_list,允许构造函数接收一个初始化列表作为参数,从而可以更方便地初始化容器或自定义类型。
  • 示例:class C { C(initializer_list<int> lt) : _arr(lt) {} private: vector<int> _arr; }; C c = {1, 2, 3, 4};

7. 返回值初始化

  • 在函数返回时,也可以使用{}来初始化返回值,这有助于确保返回值的正确性和类型安全。

8. 静态成员变量和全局变量的就地初始化

  • 在C++11中,除了构造函数初始化列表外,还允许使用={}对静态成员变量和全局变量进行就地初始化。

9. 防止类型收窄

  • 列表初始化可以防止类型收窄,即当尝试将一种类型的值初始化为另一种类型(且这种转换可能会导致精度损失或范围超出)时,编译器会报错。

总结

int a{10}; //明确表达初始化过程,避免与赋值混淆
int b{}; //空列表初始化 内置类型变量会被初始化为该类型的零值int arr1[] = {1, 2, 3};
int arr2[]{1, 2, 3};int* pa = new int[4]{ 1,2,3,4 };vector<int> v{1, 2, 3};
map<int, float> m{ {1, 1.0f}, {2, 2.0f} };struct A 
{ A(int a = 0, int b = 0) : _a(a), _b(b) {} 
}; 
A a{1, 2};template<class T> 
struct B 
{ B(T c = 0, T d = 0) : _c(c), _d(d) {} 
}; 
B<int> b{3, 4};class C 
{ C(initializer_list<int> lt) : _arr(lt) {} 
private: vector<int> _arr; 
}; 
C c = {1, 2, 3, 4};std::string createString() 
{  return {"Hello, World!"}; // 使用 {} 初始化返回值  
}static int staticVar = 42; // 使用 = 初始化  
static std::string staticStringVar{"Static String"}; // 使用 {} 初始化  int globalVar = 100; // 使用 = 初始化  
std::string globalStringVar{"Global String"}; // 使用 {} 初始化  char c1 = 256; // 可能不会报错,但值会被截断  
// char c2{256}; // 这会编译错误,因为256超出了char的表示范围  // 尝试将浮点数转换为整数,同样使用 {} 可以防止类型收窄  
float f = 3.14;  
int i1 = f; // 隐式转换,f的值被截断为整数  
// int i2{f}; // 这会编译错误,因为浮点数到整数的转换可能不安全  
int i3 = static_cast<int>(f); // 显式转换,明确意图 // 安全的转换  int main()
{auto i = { 10,20,30 };cout << typeid(i).name() << endl; // class std::initializer list<int>return 0;
}int main()
{vector<int> v1 = { 1,2,3,4,5 }; //  initializer_list构造函数list<int> l1 = { 10, 20, 30 }; //  initializer_list构造函数Date d1 = { 2024, 1, 9 }; // 参数匹配Date构造==》构造+拷贝=直接构造;// 参数不匹配,{ 2024, 1, 9, 0}被识别成 initializer_list类型,参数不匹配报错//vector& operator= (initializer_list<value_type> il);v1 = {10, 20, 30}; // 这个时候调的是赋值重载,而不是 initializer_list 的构造return 0;
}

decltype

将变量的类型声明为表达式指定的类型。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;double y = 2.2;decltype(x * y) ret;  // ret的类型是doubledecltype(&x) p;       // p的类型是int*// 类型以字符串形式获取到cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;vector<decltype(ret)> v;   // 使用 ret 的类型去实例化 vectorF(1, 'a');return 0;
}

右值引用

右值引用的出现

左值引用解决了:传引用传参 传引用返回;

左值引用无法解决:局部变量传引用返回。那么传值返回就要经历【构造+拷贝构造】

移动构造

移动构造本质是将参数右值的资源窃取过来,占为已有,就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。

https://blog.csdn.net/LHRan_ran_/article/details/133823688?fromshare=blogdetail&sharetype=blogdetail&sharerId=133823688&sharerefer=PC&sharesource=LHRan_ran_&sharefrom=from_link

// 移动构造: 传过来的s是右值 比如 返回值或 ("hello" + "world")
//ape::string ret2 = (s1 + '!'); 右值拷贝 ret2.string( (s1 + '!') );
string(string&& s) noexcept:_str(nullptr)
{cout << "  string(string&& s)    -- 右值移动拷贝" << endl;swap(s); //直接换过来s._str = nullptr;
}ape::string int_to_string(int value)
{//return str; 构造一个右值tmp + 调用移动构造 使得s获得返回值return move(str);// 这里只是为了调用我们的移动构造输出调试信息 // 实际应用中 str是一个出了函数就销毁的变量 这是错误代码 仅为演示!// ape::string s = int_to_string(1234);
}

在这里插入图片描述

c++库里移动构造的行为

在这里插入图片描述

总结

左值引用通过引用直接操作 省去中间额外的拷贝
右值引用通过识别是左值还是右值 如果是右值 直接移动拷贝

为什么要有右值引用

为了提高效率 即 右值直接移动拷贝而非深拷贝 因为拷贝时拷贝对象获取到右值的资源后 右值就不再具有价值

因为想提升效率所以搞了右值 但是移动拷贝转移资源时需要”左值“属性 于是这样被设计:s作为”右值引用“ 但是s的属性是左值!

在这里插入图片描述

完美转发–由右值引用引发的问题

Fun(forward(t));将t的属性置为原有属性 当原有属性为左值 你还是左值 是右值 你还是右值 当需要把原有属性是右值但是在该函数需要当成左值来用时 不加forward<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>
//这里是一个右值引用 当这个函数被调用 t是参数的右值引用 但是此时 t的属性变为了左值
void PerfectForward(T&& t)//模板中的 && 不代表右值引用,而是万能引用,其既能接收左值又能接收右值
{//Fun(forward<T>(t));Fun(t);
}int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(move(a));      // 右值const int b = 8;PerfectForward(b);		      // const 左值PerfectForward(move(b));      // const 右值return 0;
}

应用场景:如果不使用完美转发就只能手动把forward改成move()

在这里插入图片描述

在这里插入图片描述

右值引用的移动语义出来以后,对深拷贝的类的影响比较大,自定义类的深拷贝传值返回影响也较大,因为移动构造和移动赋值出来以后减少了它们的深拷贝;一些容器的插入接口也新增了右值版本,也减少了深拷贝。但是右值引用对于浅拷贝的类是没有意义的,因为它们没有资源可以转移

默认移动构造/赋值

在这里插入图片描述

delete default

Person(Person&& p) = delete; 		// 不让生成实现
Person(const Person& p) = default;  // 强制编译器生成

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用 default 关键字显示指定移动构造生成。

逗号表达式

逗号表达式的求值顺序是从左到右。整个逗号表达式的值是最后一个表达式的值。

特性

  1. 求值顺序:逗号表达式中的表达式按照从左到右的顺序被求值。
  2. 结果:逗号表达式的结果是最后一个表达式的值,而不是一个列表或者集合。
  3. 副作用:逗号表达式常用于利用其副作用,比如对变量进行多次赋值或调用具有副作用的函数。

示例

#include <iostream>  int main() 
{  int a = 0, b = 0;  // 逗号表达式  (a = 5, b = a + 1, a + b); // a 被赋值为 5,b 被赋值为 6,表达式的结果是 a + b = 11,但赋值给变量时仅使用最后一个表达式的值  // 注意:逗号表达式通常用于语句中,而不是直接赋值给变量  // 下面的赋值仅会接收逗号表达式的最后一个表达式的值  int result = (a = 2, b = a + 1, a + b); // result 被赋值为 3(即 a + b 的结果)  std::cout << "a = " << a << ", b = " << b << ", result = " << result << std::endl;  return 0;  
}

注意事项

逗号操作符与逗号分隔符(在函数参数列表、初始化列表等中使用的)在语法上是不同的。逗号操作符用于创建逗号表达式,而逗号分隔符用于分隔列表中的元素。

可变参数模板

template <class ...Args>
void ShowList(Args... args)
{cout << sizeof...(args) << endl;
}
int main()
{ShowList(1, 2, 3, 4, 5);ShowList(1, "abcde", 3.33);return 0;
}

展开参数包

编译时的递归推演

// 递归终止函数
void _ShowList()
{cout << endl;
}// 展开函数
template <class T, class ...Args>
void _ShowList(const T& val, Args... args)
{cout << val << " ";_ShowList(args...);
}template <class ...Args>
void ShowList(Args... args)
{_ShowList(args...);
}int main()
{ShowList(1, 2, 3, 4, 5);ShowList(1, "abcde", 3.33);return 0;
}

逗号表达式

template <class T>
void PrintArg(T t)
{cout << t << " ";
}template <class ...Args>
void ShowList(Args... args)
{// int arr[] = { PrintArg(args)... };(PrintArg(args), ...);cout << endl; 
}int main()
{ShowList(1, 2, 3, 4, 5);ShowList(1, "abcde", 3.33);return 0;
}

emplace_back

在这里插入图片描述

int main()
{list<string> lt;lt.push_back("abc");	// const char* 构造string + string移动构造nodelt.emplace_back("abc"); //  const char*直接移动构造node(完美转发)// 同样的 多参数也是如此list<pair<string,int>> lt;lt.push_back(make_pair("abc",1));lt.emplace_back("abc",1);return 0;
}

修改list模拟实现类

template <class... Args>
list_node(Args&&... args)
: _data(args...)
, _next(nullptr)
, _prev(nullptr)
{}template <class... Args>
void emplace_back(Args&&... args)
{Node* newnode = new Node(args...);// 链接节点
}

在这里插入图片描述

仿函数

在这里插入图片描述

function的构造函数接收Functor()的临时对象将其封装为一个可调用对象

class TD
{
public:void operator()(){cout << "Thread3" << endl;}
};int main()
{function<void()> f = TD();f();TD td;f = td;f();// 线程函数为仿函数thread t1((TD())); // ( TD() ) 必须这样写 原因不明 不重要thread t2(td);t1.join();t2.join();cout << "Main thread!" << endl;return 0;
}

function包装器/适配器/类模板

https://blog.csdn.net/LHRan_ran_/article/details/133930224?fromshare=blogdetail&sharetype=blogdetail&sharerId=133930224&sharerefer=PC&sharesource=LHRan_ran_&sharefrom=from_link

// 类模板原型如下
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

通过给这些可调用对象加上一层包装器,使得函数模板只实例化一份

function的构造函数接收Functor()的临时对象将其封装为一个可调用对象

在这里插入图片描述

包装器的应用

class Solution
{typedef long long Long;
public:int evalRPN(vector<string>& tokens){stack<Long> st;map< string, function<Long(Long, Long)> > m ={{"+", [](Long a, Long b) { return a + b; }},{"-", [](Long a, Long b) { return a - b; }},{"*", [](Long a, Long b) { return a * b; }},{"/", [](Long a, Long b) { return a / b; }}};for (auto& e : tokens){if (m.count(e)){Long right = st.top();st.pop();Long left = st.top();st.pop();st.push(m[e](left, right));}elsest.push(stoll(e));}return st.top();}
};

bind函数模板/包装器/适配器

  1. 接收一个可调用对象(callable object),生成一个新的可调用对象“适应”原对象的参数列表

调整参数顺序

int Sub(int a, int b)
{return a - b;
}int main()
{function<int(int, int)> f1 = Sub;cout << f1(10, 5) << endl;// 调整参数顺序function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);cout << f2(10, 5) << endl;// 10传给b 5传给areturn 0;
}

调整参数个数

int main()
{function<int(int, int)> f1 = Sub;cout << f1(10, 5) << endl;// 调整参数个数,有些参数可以使用 bind 时固定function<int(int)> f3 = bind(Sub, 20, placeholders::_1);cout << f3(5) << endl;//20给a 5给breturn 0;
}

调整参数个数的应用

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{// 静态成员函数名会自动退化为指向该函数的指针 // 写成&Plus::plusi也对 没必要function<int(int, int)> f1 = Plus::plusi;cout << f1(1, 2) << endl;// 普通成员函数 必须加&function<double(Plus*, double, double)> f2 = &Plus::plusd;Plus ps;cout << f2(&ps, 1.1, 2.2) << endl;// 这里传 Plus 编译器会进行特殊处理,实际上是 Plus*function<double(Plus, double, double)> f3 = &Plus::plusd;cout << f3(Plus(), 1.11, 2.22) << endl;// 通过提前bind简化调用的编写并显得统一function<double(double, double)> f4 = bind(&Plus::plusd, Plus(), placeholders::_1, placeholders::_2);cout << f4(1.11, 2.22) << endl;return 0;
}

应用

在这里插入图片描述

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

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

相关文章

使用Pytorch构建自定义层并在模型中使用

使用Pytorch构建自定义层并在模型中使用 继承自nn.Module类&#xff0c;自定义名称为NoisyLinear的线性层&#xff0c;并在新模型定义过程中使用该自定义层。完整代码可以在jupyter nbviewer中在线访问。 import torch import torch.nn as nn from torch.utils.data import T…

IP 数据包分包组包

为什么要分包 由于数据链路层MTU的限制,对于较⼤的IP数据包要进⾏分包. 什么是MTU MTU相当于发快递时对包裹尺⼨的限制.这个限制是不同的数据链路对应的物理层,产⽣的限制. • 以太⽹帧中的数据⻓度规定最⼩46字节,最⼤1500字节,ARP数据包的⻓度不够46字节,要在后⾯补填 充…

IDEA在git提交时添加忽略文件

在IntelliJ IDEA中&#xff0c;要忽略target目录下所有文件的Git提交&#xff0c;你可以通过设置.gitignore文件来实现。以下是步骤和示例代码&#xff1a; 1、打开项目根目录下的.gitignore文件。也可以先下载这个.ignore插件。 2、如果不存在&#xff0c;利用上面的插件新建…

Stable Diffusion绘画 | 来训练属于自己的模型:炼丹参数调整--步数设置与计算

要想训练一个优质的模型&#xff0c;一定要认识和了解模型训练中&#xff0c;参数的作用和意义。 整个模型训练的过程&#xff0c;参数并不是一成不变的&#xff0c;也没有固定的模板&#xff0c; 当我们修改了模型训练里面的某个参数&#xff0c;很可能就需要连带其他一系列…

五.运输层

目录 5.1概述 5.2传输层的寻址与端口 熟知端口号 套接字(Socket) 5.3 UDP 特点 UDP报文格式 UDP校验 二进制反码求和 5.4 TCP 特点 可靠传输 停止等待协议 流水线方式 累计应答 流量控制 滑动窗口 拥塞控制 三次握手&#xff0c;四次握手 5.1概述 只有主机…

首屏优化之:SSR(服务端渲染)

引言 今天我们来聊一下首屏优化之SSR-服务端渲染&#xff08;Server-Side Rendering&#xff09;。 可能很多朋友并不了解什么是 SSR&#xff0c;包括在工作中写的网站是什么类型的也不太清楚&#xff0c;是 CSR 还是 SSR&#xff1f;作者在阅读过大量的文章之后&#xff0c;…

MySQL进阶篇 - 存储引擎

01 MySQL体系结构 【1】索引是在存储引擎层实现的&#xff0c;不同的存储引擎&#xff0c;索引的结构是不一样的。 【2】InnoDB引擎是MySQL5.5版本之后默认的存储引擎。 【3】MySQL体系结构分为客户端和服务器&#xff0c;服务器又分为4个层次。 02 存储引擎简介 【1】引擎…

C--编译和链接见解

欢迎各位看官&#xff01;如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论 感谢各位看官的支持&#xff01;&#xff01;&#xff01; 一&#xff1a;翻译环境和运行环境 在ANSIIC的任何一种实现中&#xff0c;存在两个不同的环境1&#xff0c;…

BugReport中的App Processor wakeup字段意义

一、功耗字段意义&#xff1a; App processor wakeup:Netd基于xt_idletimer 待机下监视网络设备的收发工作状态&#xff0c;即当设备发生联网从休眠态变成为唤醒态时&#xff0c;会记录打醒者的uid(uid大于0)和网络类型(wifi或数据类型)、时间戳 实际日志&#xff1a;我们在B…

【Streamlit案例】制作销售数据可视化看板

目录 一、案例效果 二、数据分析 三、加载数据 四、网站前端 &#xff08;一&#xff09;网页标题和图标 &#xff08;二&#xff09;侧边栏和多选框 &#xff08;三&#xff09;主页面信息 ​&#xff08;四&#xff09;主页面图表 &#xff08;五&#xff09;隐藏部…

微信小程序操作蓝牙

主要流程&#xff1a; 1.初始化蓝牙适配器openBluetoothAdapter&#xff0c;如果不成功就onBluetoothAdapterStateChange监听蓝牙适配器状态变化事件 2.startBluetoothDevicesDiscovery开始搜寻附近的蓝牙外围设备 3.onBluetoothDeviceFound监听寻找到新设备的事件&#xff0c;…

用Python+flask+mysql等开发的Excel数据资产落地工具

话不多说 1)Excel文件上传,列表预览 2)选中要导入结构及数据的Excel文件 约束说明: 2.1)Excel文件的第一行约定为表头名称 2.2)系统自动识别字段列名及数据类型,目前不支持合并表头 3)Excel建表导入数据成功后,可在表源列表中预览查看 4)对数据表源可进行透视图设计管理,可对…

可以无限次使用o1-mini和o1-preview模型API接口的方法,并且比便宜便宜7倍以上

打开网站 https://open.xiaojingai.com 然后点击令牌页面&#xff0c;生成令牌&#xff0c;令牌就是api-key

Hive数仓操作(一)

Hive 介绍 Hive 是一个基于 Hadoop 的数据仓库工具&#xff0c;旨在简化大规模数据集的管理和分析。它将结构化数据文件映射为表&#xff0c;并提供类似 SQL 的查询功能。Hive 的数据存储在 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;中&#xff0c;使用 Hive 查询语…

12.梯度下降法的具体解析——举足轻重的模型优化算法

引言 梯度下降法(Gradient Descent)是一种广泛应用于机器学习领域的基本优化算法&#xff0c;它通过迭代地调整模型参数&#xff0c;最小化损失函数以求得到模型最优解。 通过阅读本篇博客&#xff0c;你可以&#xff1a; 1.知晓梯度下降法的具体流程 2.掌握不同梯度下降法…

数据仓库简介(一)

数据仓库概述 1. 什么是数据仓库&#xff1f; 数据仓库&#xff08;Data Warehouse&#xff0c;简称 DW&#xff09;是由 Bill Inmon 于 1990 年提出的一种用于数据分析和挖掘的系统。它的主要目标是通过分析和挖掘数据&#xff0c;为不同层级的决策提供支持&#xff0c;构成…

云服务架构与华为云架构

目录 1.云服务架构是什么&#xff1f; 1.1 云服务模型 1.2 云部署模型 1.3 云服务架构的组件 1.4 云服务架构模式 1.5 关键设计考虑 1.6 优势 1.7 常见的云服务架构实践 2.华为云架构 2.1 华为云服务模型 2.2 华为云部署模型 2.3 华为云服务架构的核心组件 2.4 华…

【C++】STL标准模板库容器set

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;关联式容器set(集合)简介 &#x1f4cc;set(集合)的使用 &#x1f38f;set(集合)的模板参数列表 &#x1f38f;set(集合)的构造函数 &#x1f38f;set(集合)的迭代…

翔云 OCR:发票识别与验真

在数字化时代&#xff0c;高效处理大量文档和数据成为企业和个人的迫切需求。翔云 OCR 作为一款强大的光学字符识别工具&#xff0c;在发票识别及验真方面表现出色&#xff0c;为我们带来了极大的便利。 一、翔云 OCR 简介 翔云 OCR 是一款基于先进的人工智能技术开发的文字识别…

搭建k8s集群服务(kubeadm方式)

准备工作 操作系统版本&#xff1a;CentOS Linux release 7.9.2009 (Core) 虚拟机硬件配置&#xff1a;2核8G内存&#xff08;最低2G&#xff09;&#xff0c;硬盘最低25G&#xff1b; linux内核版本&#xff08;3.10版本尝试失败&#xff09;&#xff1a;5.4.268-1.el7.elr…