『C++11』基础新特性

🔥博客主页 小羊失眠啦.
🎥系列专栏《C语言》 《数据结构》 《C++》 《Linux》
❤️感谢大家点赞👍收藏⭐评论✍️


前言

自从C++98以来,C++11无疑是一个相当成功的版本更新。它引入了许多重要的语言特性和标准库增强,为C++编程带来了重大的改进和便利。C++11的发布标志着C++语言的现代化和进步,为程序员提供了更多工具和选项来编写高效、可维护和现代的代码

在这里插入图片描述


一、C++11 简介

1.1 起源

1998C++标准委员会 成立后,计划每五年进行一次更新

2003C++标准委员会 提交了一份 技术勘误表(简称为 TC1),TC1 主要是对 C++98 标准中的漏洞进行修复,其语言的核心部分并没有大改动,这次提交可以看作一次小小的语法更新,即 C++03,但因此人们总是习惯性的将 C++98/03 看作一个标准,多年以来,C++98/03 标准是市面上主要被使用的 C++ 版本

C++标准委员会 计划在 2007 年发布下一个语法版本,并计划命名为 C++07,但是很遗憾,在 2006 年,官方觉得无法在 2007 年如期发布 C++07,并且觉得 2008 年可能也无法完成,于是官方干脆将下一个 C++ 标准命名为 C++0XX 表示有可能在 07、08、09 年完成)。结果时间来到了 2010 年,官方还是没有完成新标准的制定,这时候大部分人觉得 C++ 新标准的发布已经遥遥无期了,最终官方在 2011 年终于完成了新标准的制定,并将新标准命名为 C++11,也就是本文中将要学习的新标准

C++11足足鸽了六年才发布了一个新版本…要知道隔壁Java可是每两年乃至每六个月更新一次新标准,现在最新的版本已经来到了JDK21

1.2 主要更新

C++11 相对于 C++98/03 来说,带来了数量可观的变化, 其中包含了约 140 个新特性,以及对 C++98/03 中约 600 个缺陷修正,这就使得 C++11 更像是一次变革,变成了一种 “新的语言”(因为 C++11 中的部分操作显得很不 C++

在这里插入图片描述

源于 C++11 官网:https://en.cppreference.com/w/cpp/11

相对于上一个标准来说,C++11 能更好的适用于系统开发和库开发:语法变得更加丰富和简单化、更加稳定和安全,总的来说,C++11 变得更强了,作为开发工具能提高程序员的开发效率,并且大多数公司项目都已支持 C++11,所以 C++11 需要重点学习和掌握

除了 C++11 外,后面还陆续推出了 C++14C++17C++20 标准,最新的 C++23 也已经发布,新标准意味着新特性,是需要慢慢适应的,并且 C++14/17 也只是对 C++11 的修复和补充,所以我们着重学习 C++11 即可

以下是不同的编译器对 C++11 语法的支持情况(绿色表示最低支持版本,红色表示不支持)

在这里插入图片描述

主流的编译器有:GCCClangMSVC,其中 GCC 就是在 Linux 中使用的编译器,基本上 GCC 4.6 及后续版本就能对 C++11 进行很好的支持,而 MSVC 是微软 VS 系列的编译器,从 VS 2015 及后续版本对 C++11 语法支持较好

推荐使用 VS 2019VS 2022 进行 C++11 新标准的学习

注:C++11 中的新特性众多,本文以及后续文章只是列举常用语法


二、列表初始化

列表初始化 { } 是我们学习的第一个 C++11 新特性,这玩意其实我们在 C语言 阶段就已经使用过了,比如对数组进行初始化 int arr[] = {1, 2, 3}

C++11 中对 { } 进行了全面升级,使其不仅能初始化数组,还能初始化自定义类型,比如 STL 中的容器,这对于编码时初始化是十分友好的

2.1 对于内置类型

首先需要明白,为了适应 泛型编程C++ 中的内置类型(比如 intdouble 等)就已经全部配备了 构造函数,方便在进行模板传参时,传递默认构造值

int main()
{// 内置类型基本都配备了构造函数int a(10);char b('x');cout << a << " " << b << endl;return 0;
}

在这里插入图片描述

C++11 中,扩大了 { } 的适用范围,使其不止能给数组初始化,也能给内置类型初始化

int main()
{// 不仅能给数组初始化,也能给内置类型初始化int arr[] = { 1, 2, 3 };int a = { 10 };char b = { 'x' };cout << arr[0] << " " << a << " " << b << endl;return 0;
}

在这里插入图片描述

如何做到的呢?

其实就是当内置类型使用 { } 初始化时,实际上是在调用它的构造函数进行构造

这就不奇怪了,无非就是让内置类型将 { } 也看做一种特殊的构造:构造 + 拷贝构造 优化为 直接构造

我们可以通过一个简单的 日期类 来体现这一现象

简单日期类 Date

// 日期类
class Date
{
public:Date(int d, int m, int y):_day(d), _month(m), _year(y){}private:int _day;int _month;int _year;
};

此时可以直接通过 列表初始化 { } 来初始化日期类对象

int main()
{Date d1 = { 2023, 11, 8 };return 0;
}

编译运行,并无报错或警告,C++11 中甚至允许省略 = 符号,使其与 拷贝构造函数 一样,直接通过对象构造对象(语法支持,但不推荐这样写,因为容易与 构造函数 混淆)

Date d2{ 2023, 11,8 };

言归正传,接下来证明 列表初始化 实际上就是 构造 + 拷贝构造 优化为 直接构造,首先是使用 explicit 修饰 Date 的构造函数,使其不能被编译器隐式优化

explicit Date(int d, int m, int y):_day(d), _month(m), _year(y)
{}

接下来同样的代码,尝试编译,结果出现了错误

在这里插入图片描述

现在的情况是 d1 列表初始化失败,d2 列表初始化成功

这是因为 d1 是由 构造 + 拷贝构造 优化后进行的构造,而 explicit 关键字可以杜绝编译器这种 隐式 优化行为,编译器无法优化,也就无法构造 d1 了;而 d2 相当于直接调用了 拷贝构造函数,不受优化的影响,也就没啥问题

这里主要是想说明一个东西:对于内置类型来说,列表初始化 { } 实际上就相当于调用了内置类型的构造函数,构造出了一个对象

2.2 对于自定义类型

列表初始化 对于内置类型来说显得多余了,但对自定义类型就不一样了,这玩意能让自定义类型的初始化变得更加简单

举个例子:想要一个内容为 1, 2, 3, 4, 5vector

如果在 C++11 之前,需要先构建一个 vector 对象,然后再 push_back 五次,非常的朴实无华

int main()
{// C++11 之前vector<int> arr;for (int i = 0; i < 5; i++)arr.push_back(i + 1);return 0;
}

足够麻烦吧?可能有的人会说我们都是直接使用 { } 初始化的,没错,你使用的正是 列表初始化 这个新特性,只是你没有发现罢了

int main()
{// C++11 之后vector<int> arr = { 1, 2, 3, 4, 5 };return 0;
}

不止可以初始化五个数,初始化十个乃至一百一千个都是可以的,显然此时的 列表初始化 调用的不是 vector 的构造函数,因为它的构造函数总不可能重载出 N 个吧?

所以对于诸如 vector 这种自定义类型来说,需要把 列表初始化 视作一个类型,然后重载对这个类型参数的构造函数就行了,于是 initializer_list<T> 类就诞生了,这是一个模板类,大概长这样

在这里插入图片描述

支持传入模型参数 T,当我们写出 { 1, 2, 3, 4, 5 } 时,实际上已经构建出了一个 initializer_list<int> 类的匿名对象,可以借助 typeid 查看类型名来证明

int main()
{// 自动推导类型auto arr = { 1, 2, 3, 4, 5 };cout << typeid(arr).name() << endl;return 0;
}

结果是 initializer_list<int> 吧?

在这里插入图片描述

所以说当我们写出这种东西时:{ T, T, T }
编译器实际已经特殊处理过了,生成了一个模板类型为 T 的匿名对象:initializer_list<T>

当然也是可以直接创建一个 initializer_list<T> 对象来初始化,initializer_list<T> 这个类的构成十分简单,其成员函数仅有 size()begin()end(),也就是支持迭代器遍历其中的数据

细节:initializer_list<T> 类支持迭代器,自然也就支持范围 for 这个新特性,可以试着用一下

格局打开,其他类中只需重载一个类型为 initializer_list<T> 的参数,并在其中通过

initializer_list<T> 对象的迭代器进行数据遍历,就能轻松获取 initializer_list<T> 对象中的数据,所以在 C++11 中,几乎对所有库中的容器进行了更新:新增参数类型为initializer_list<T> 的构造函数,这里简单举出几个例子

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

但凡重载了 initializer_list<T> 的构造函数,就能轻松使用 列表初始化 来初始化对象,如果没重载呢?那就不支持,比如我们之前模拟实现的 vector (代码太长了,这里就不放完整代码了,重点在于看现象)

在这里插入图片描述

直接就报了一个错误,前面说过,要先支持 列表初始化 也很简单,重载一个参数为 initializer_list<T> 的构造函数就好了,比如这样

重载了 initializer_list<T> 的构造函数 ---- 位于 vector 类(模拟实现)

// 供列表初始化调用
vector(const std::initializer_list<T>& init)
{std::initializer_list<T>::iterator it = init.begin();while (it != init.end()){this->push_back(*it);++it;}
}

这么一看没啥毛病,但如果一编译就会出问题

在这里插入图片描述

这是因为 C++11 提高了安全检查,对于具有二义性的行为是直接拒之门外的,比如这里的

std::initializer_list<T>::iterator it = init.begin();

此时编译器不知道 it 究竟是 std::initializer_list<T>::iterator 中的一个静态变量,还是一个迭代器类型,所以编译器直接选择了报错,如果是在 C++11 之前,可能可以成功编译,这是因为检查不严格

要想解决问题就需要使用 typename 关键字,直接告诉编译器:std::initializer_list<T>::iterator 就是一个类型,并且 it 就是一个新建变量,此时就不会报错了

// 供列表初始化调用
vector(const std::initializer_list<T>& init)
{typename std::initializer_list<T>::iterator it = init.begin();while (it != init.end()){this->push_back(*it);++it;}
}

此时再编译,我们自己模拟实现的 vector 就能支持 列表初始化 了,C++11 对库中类的更新也是如此,并不神秘

库中不仅新增了对 initializer_list<T> 的构造重载,也顺便更新了对 initializer_list<T> 的赋值重载,所以是可以直接将一个 initializer_list<T> 对象赋值给容器对象的

2.3 高效的玩法

为什么说 列表初始化 是个好东西呢?

因为它可以帮我省很多初始化方面的事,比如对 pair 对象的初始化

int main()
{// 快速构建一个词典unordered_map<string, string> hash ={{"banana", "香蕉"},{"apple", "苹果"},{"pear", "梨"}};// 亦或是快速插入hash.insert({ "watermelon", "西瓜" });return 0;
}

有了这玩意,还要什么 make_pair

总之,列表初始化 就像一个万金油,得益于 泛型编程,可以轻松进行初始化,并且是 万能初始化,可以在刷题过程中享受一下了


三、简化声明

C++11 省去了很多麻烦事,可以让用户在使用时更加轻松,这也让 C++ 显得不那么 C++(做了很多用户看不见的操作),顺应时代发展变味了,比如接下来这几个声明,就是 C++11 为了简化模板操作时的补丁

3.1 auto 自动推导类型

auto 意味自动,这个关键字早在 C++98 中就已经存在了,主要用来 表明变量是局部自动存储类型,但如今在局部域中定义的局部变量默认就是自动存储类型,因此原来的 auto 显得很没用

组委会在 C++11 中废弃原来的用法,对 auto 进行了重新设计,使其摇身一变,成为一个非常好用且实用的关键字:根据待赋给变量的参数,自动推导其参数类型,用户无需关心该变量要定义为什么类型

auto 常常用于推导 复杂类型

比如哈希表中的迭代器

int main()
{unordered_map<int, int> hash = { {1, 1} };auto it = hash.begin();cout << typeid(it).name() << endl;return 0;
}

可以看到 it 的类型非常非常长,就问你如果手动定义这么一个类型的变量,方便吗?

在这里插入图片描述

有了 auto 就不用担心了,直接从手动挡变成了自动挡,什么半坡起步不是轻松拿捏

不过使用 auto 也得注意以下几点:

  1. auto 定义的变量必须是显示实例化的,也就是 = 右边的变量类型是可知的
  2. auto 不能作为参数类型

3.2 decltype 获取推导类型

除了 auto 这个自动挡外,C++11 还提供了另一个自动挡 decltype,不过这个自动挡使用起来比较麻烦,需要指明参数,才能推导出类型

int main()
{unordered_map<int, int> hash = { {1, 1} };auto it = hash.begin();decltype(it) tmp;cout << typeid(tmp).name() << endl;return 0;
}

在这里插入图片描述

decltypeauto 方便的一点是 decltype 无需显式实例化,也就是单纯定义也行

decltype 还可以作为模板参数传递,而 auto 不行

// decltype 可以推导出参数类型,并进行传递
vector<decltype(it)> v1;

auto 方便,decltype 更强大,但使用更麻烦,可以根据具体需求灵活使用

3.3 nullptr 空值补丁

祖师爷在设计 C++ 时,留下了个空值 NULL 的坑,不小心把 0 设成了 指针空值,同时也设置成了 整型空值,这是典型的二义性,在进行参数传递时,编译器无法区别

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

于是为了填补这个坑,组委会在 C++11 中推出了空值补丁 nullptr,专门用来表示 指针空值,以后想把指针赋为空指针时,可以使用 nullptr


四、范围 for

范围 for 是一块语法糖,使用起来及其舒适,可以一键遍历容器中的值,如此申请的语法,背后其实就是对迭代器遍历的封装

简单使用范围 for 遍历链表

int main()
{// 使用列表初始化list<int> l = { 1, 2, 3, 4, 5 };for (auto e : l)cout << e << " ";return 0;
}

在这里插入图片描述

范围 for 的语法为

for(类型 值 : 容器)
{// 对值进行操作(默认不可被修改)
}

配合 auto 自动推导类型,范围 for 就会变得非常香

范围 for 的本质其实就是 迭代器 遍历,只要容器支持 迭代器,那么就可以支持范围 for

比如使用 范围 for 遍历哈希表时,实际获取的就是哈希表中的 pair

int main()
{unordered_map<int, int> hash = { {1, 1}, { 2, 2 } };for (auto it : hash)cout << it.first << " " << it.second << endl;return 0;
}

在这里插入图片描述

注意: 范围 for 中获取的值,默认是不可被修改的,如果想要修改,需要使用 引用类型 获取值

接下来演示使用 范围 for 修改容器中的值,并打印进行对比

int main()
{// 使用列表初始化list<int> l = { 1, 2, 3, 4, 5 };for (auto& e : l){cout << e << " ";e++;}cout << endl;for (auto e : l)cout << e << " ";return 0;
}

在这里插入图片描述

可以看到 list 中的值已经被修改了


五、智能指针

智能指针 这个名词听着挺唬人,其实也没啥,无非就是会自动销毁 new 出来的对象,对于日常使用来说,还是挺方便的,毕竟 C/C++ 可没有隔壁 Java 的垃圾回收机制 GC,得自己清理垃圾, 智能指针 可以自动完成垃圾清理这个工作

5.1 RALL 风格

RAII 风格由祖师爷 本贾尼 提出,他说 使用局部对象管理资源的技术通常称为“资源获取就是初始化”,这种通用技术依赖于构造函数和析构函数的性质以及它们与异常处理的交互作用

简单来说就是 构造即初始化,析构则销毁,利用对象创建时需要调用 构造函数,生命周期结束时会自动调用 析构函数 的特性

智能指针 就是一个对象,一个在构造时申请资源,析构时释放资源的小工具,仅此而已

5.2 智能指针分类

C++11 中的 智能指针unique_ptrshared_ptrweak_prr,其中 weak_ptr 就是 shared_ptr 的小弟;而 unique_ptrshared_ptr 的区别在于 是否支持拷贝

如果想传递 智能指针 的话,选择 shared_ptr,否则选择 unique_ptr 就行了

下面简单演示一下 unique_ptr 是如何 智能 管理资源的,使用 智能指针 需要包含头文件 memory

class A
{
public:A(){cout << "调用了构造函数" << endl;}~A(){cout << "调用了析构函数" << endl;}
};int main()
{unique_ptr<A> ptr(new A);return 0;
}

在这里插入图片描述

可以看到析构函数确实被调用了,证明资源已经被销毁了

关于 智能指针 还有很多知识,后面会专门出一篇文章来详谈 智能指针,这里就不再赘述


六、STL容器变化

C++11 不仅更新了 C++ 语法,还更新了 STL 库,作为 C++ 联邦中的重要成员,STL 库是编程时必不可少的利器,不仅好用,而且高效

6.1 新增容器

C++11STL 增加了几种新容器,比如之前已经模拟实现过的 unordered_mapunordered_set 就是新增的容器,C++11 中共新增了这四种容器

在这里插入图片描述

array 是一个静态数组,使用时需要像 C语言 中的数组一样确定大小,后续使用时无法插入或删除数据,array 提供的接口如下

在这里插入图片描述

对比 C语言 传统静态数组,进行了以下升级

  • 面向对象,成为一个单独的类
  • 提供迭代器,支持通过迭代器遍历
  • 可以更轻易获取大小信息
  • 对于数据的访问方式更加丰富,同时下标随机访问时,安全性更高
  • 支持其他功能:判满、交换

这么看来似乎是全面升级,但别忘了,vector 是全面碾压 arrayvector 配合 resize 或者 reserve,也能做到提前开辟容量,同时 vector 接口更加丰富,兼容性也更好

所以实际上 array 很少用,这种东西仁者见仁智者见智吧


再来说说另一个新增容器 forward_list,传统的 list 是一个双向循环链表,支持 首尾操作,而 forward_list 是一个很单纯的 单链表,并且是一个不支持尾部操作的 单链表,尽管它提供任意位置插入/删除的接口,但就是没有明着提供尾部操作接口

在这里插入图片描述

forward_list 只有一个指针,节省空间,同时头部操作效率不错,但是我们日常中都是不缺内存的,所以 list 会更加方便

至于 unordered_mapunordered_set 就不再细谈了,无非就是 哈希表 的实际运用,效率极高

6.2 新增接口

除了新增容器,还给原来的容器进行了接口方面的升级,这里以 vector 为例,谈谈几个升级点

  1. 重载了 initializer_list<T>,使容器初始化更加方便

在这里插入图片描述

  1. 增加 const 对象的迭代器获取,也就是 cbegincend,这玩意其实很鸡肋,因为普通版的 beginend 都已经重载了 const 版本

在这里插入图片描述

  1. 支持移动构造和移动赋值,可以极大提高效率(重点)

在这里插入图片描述

  1. 支持右值引用相关插入接口,同样可以提高效率(重点)

在这里插入图片描述

总的来看,C++11 还是更新了不少东西,不过万众期待的 网络库 仍迟迟没有更新,希望网络相关标准库可以尽快更新吧,让 C++ 变得更加强大

C++11 的重磅更新为 右值引用和移动语义、lambda表达式、线程库、包装器等,限于篇幅原因,这些重磅更新将会放到后面的文章中详细讲解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

相关文章

ADS基础教程21 - 电磁仿真(EM)模型的远场和场可视化

模型的远场和场可视化 一、引言二、操作步骤1.定义参数2.执行远场视图&#xff08;失败案例&#xff09;3.重新仿真提取参数 三、总结 一、引言 本文介绍电磁仿真模型的远场和场可视化。 二、操作步骤 1.定义参数 1&#xff09;在Layout视图&#xff0c;工具栏中点击EM调出…

【递归、搜索与回溯】综合练习二

综合练习二 1.组合2.目标和3.组合总和4.字母大小写全排列 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.组合 题目链接&#xff1a;77. 组…

RabbitMQ实践——定制一致性Hash交换器的路由字段

大纲 Property法定制交换器绑定队列测试 Header法定制交换器绑定队列测试 参考资料 在《RabbitMQ实践——利用一致性Hash交换器做负载均衡》一文中&#xff0c;我们熟悉了一致性Hash交换器的使用方法。默认的&#xff0c;它使用Routing key来做Hash的判断源。但是有些时候&…

Maven 快速入门

Maven 简介 Maven是apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 依赖管理 方便快捷的管理项目的依赖资源(jar包),避免版本冲突 配置 依赖: 指当前项目运行所需要的(jar包) 在pom.xml 中编写<dependencies> 标签 在<dependencies…

线程池监控是怎么做的?

引言&#xff1a;在现代软件开发中&#xff0c;线程池是一种重要的并发控制机制&#xff0c;它能有效管理和复用线程资源&#xff0c;提升系统的性能和响应速度。然而&#xff0c;随着应用规模的扩大和复杂性的增加&#xff0c;对线程池进行有效监控显得尤为重要。线程池监控不…

bellman-ford——AcWing 853. 有边数限制的最短路99

bellman-ford 定义 贝尔曼-福特&#xff08;Bellman-Ford&#xff09;算法是一种用于在加权有向图中计算单源最短路径的算法。 运用情况 可以处理存在负权边的图。常用于找出图中从一个特定顶点到其他所有顶点的最短路径。 注意事项 时间复杂度相对较高。如果图中包含从源…

计算机毕业设计Django+Vue.js考研推荐系统 考研分数线预测 中公考研爬虫 混合神经网络推荐算法 考研可视化 机器学习 深度学习 大数据毕业设计

Python数据分析与可视化期末项目报告 项目名称&#xff1a; 考研推荐系统数据分析与可视化 学 号&#xff1a; 姓 名&#xff1a; …

【PHP开发工程师系统性教学】——thinkPHP的分页操作,不管有几页,用这个你想分几页就分几页

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

MoneyPrinterPlus:AI自动短视频生成工具,详细使用教程

MoneyPrinterPlus是一款使用AI大模型技术,一键批量生成各类短视频,自动批量混剪短视频,自动把视频发布到抖音,快手,小红书,视频号上的轻松赚钱工具。 之前有出过一期基本的介绍&#xff0c;但是后台收到有些小伙伴说&#xff0c;不知道如何使用。 今天我将会手把手的详细介绍…

怎么加密U盘数据?U盘加密软件哪个好?

U盘是我们在生活和工作中最常用的移动存储设备&#xff0c;而为了避免U盘数据泄露&#xff0c;我们需要使用U盘加密软件来加密保护U盘数据。那么&#xff0c;U盘加密软件哪个好呢&#xff1f;下面我们就一起来了解一下吧。 BitLocker加密 BitLocker是Windows系统提供的磁盘加密…

多种传感器在钢铁工业安全风险监测预警中的应用

中国作为钢铁行业的生产与消费大国&#xff0c;其钢铁冶炼流程的复杂性和长周期性使得各环节中频繁出现的有毒有害、易燃易爆气体以及粉尘等危险物质成为行业安全管理的重大挑战。为了保障工作人员的安全&#xff0c;多种传感器在安全风险监测预警中的应用显得尤为重要。 钢铁产…

java从红外图片提取温度,计算超过阈值的温度占总面积的百分比

灰度图是单通道图&#xff0c;像素只有一个值&#xff1a;灰度值。灰度值越高&#xff0c;则图像越亮。 现在我们已经知道我们看到一张灰度图是由许多不同灰度值的像素点构成&#xff0c;而每个像素就是一个越亮的像素&#xff0c;灰度值越高&#xff0c;最高值是255&#xff…

Latex的参考文献中显示三个问号???——解决办法

1、问题描述 在使用spring模板&#xff0c;并引用book时&#xff0c;末尾的引文地方出现三个???由于使用的bibtex是直接从谷歌学术中导出来的&#xff0c;其中仅包含作者&#xff0c;书名&#xff0c;出版社&#xff0c;年份等&#xff0c;缺少了重要的信息。结果导致在出版…

什么!没有Starter的阿里云OSS也能集成到SpringBoot?

实际上&#xff0c;我们在Maven存储库中尝试搜索阿里云OSS。在此过程中&#xff0c;我们会发现阿里云官方未提供一种集成Spring Boot的模式&#xff0c;即xxx-Springboot-Starter&#xff0c;显然&#xff0c;这是一个需要自行定制的组件。然而&#xff0c;如今许多企业在研发过…

LeetCode | 520.检测大写字母

这道题直接分3种情况讨论&#xff1a;1、全部都为大写&#xff1b;2、全部都为小写&#xff1b;3、首字母大写其余小写。这里我借用了一个全是大写字母的串和一个全为小写字母的串进行比较 class Solution(object):def detectCapitalUse(self, word):""":type …

【机器学习】计算机图形和深度学习模型NeRF详解(1)

1.引言 1.1.1. NeRF研究的背景 人们在拍照的时候&#xff0c;往往会中各个角度进行拍摄&#xff0c;以呈现出物体的全貌和美丽。下图的照片&#xff0c;拍摄的是一架楼梯&#xff0c;但是拍摄的角度完全不同&#xff1a; 我们可以看到这些图片都是楼梯的照片&#xff0c;但拍…

Training language models to follow instructions with human feedback 论文阅读

论文原文&#xff1a;https://arxiv.org/pdf/2203.02155 论文简介 语言模型越大并不意味着它能更好的理解用户的意图&#xff0c;因此在这篇论文中&#xff0c;展示了根据人的反馈对模型进行微调&#xff0c;使得语言模型能够在各种人物上更好的理解用户的意图。在评估中&…

树莓派4B学习笔记11:PC端网线SSH连接树莓派

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 今日学习使用网线连接树莓派&#xff0c;网线可以提供更…

使用 C# 学习面向对象编程:第 8 部分

抽象方法 亲爱的读者&#xff0c;本文是 OOP 的第四大支柱&#xff0c;也是最后一大支柱。对于 OOP 初学者来说&#xff0c;这很容易让人困惑。因此&#xff0c;我们用非常简单的语言提供了一个示例。 “抽象用于管理复杂性。无法创建抽象类的对象。抽象类用于继承。” 例如…

降噪领夹麦克风哪个牌子好?揭秘无线领夹麦克风哪个降噪好

相信很多新手视频创作者都有一个疑问&#xff1a;为什么别人的视频或者直播音质这么清晰&#xff0c;几乎没什么噪音呢&#xff1f;其实最主要的就是麦克风的原因&#xff0c;相机或手机内置的麦克风是无法提供高质量的音频记录以及很好的指向性的。 想要拍摄出来的视频作品拥有…