C++11『基础新特性』

✨个人主页: 北 海
🎉所属专栏: C++修行之路
🎃操作环境: Visual Studio 2022 版本 17.6.5

成就一亿技术人


文章目录

  • 🌇前言
  • 🏙️正文
    • 1.C++11 简介
      • 1.1.起源
      • 1.2.主要更新
    • 2.列表初始化
      • 2.1.对于内置类型
      • 2.2.对于自定义类型
      • 2.3.高效的玩法
    • 3.简化声明
      • 3.1.auto 自动推导类型
      • 3.2.decltype 获取推导类型
      • 3.3.nullptr 空值补丁
    • 4.范围 for
    • 5.智能指针
      • 5.1.RAII 风格
      • 5.2.智能指针分类
    • 6.STL容器变化
      • 6.1.新增容器
      • 6.2.新增接口
  • 🌆总结


🌇前言

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


🏙️正文

1.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 中的新特性众多,本文以及后续文章只是列举常用语法


2.列表初始化

列表初始化 { } 是我们学习的第一个 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 的构造函数,使其不能被编译器隐式优化

构造函数 Date — 位于 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 就是一个新建变量,此时就不会报错了

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

// 供列表初始化调用
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

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


3.简化声明

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


4.范围 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 中的值已经被修改了


5.智能指针

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

5.1.RAII 风格

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

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

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


6.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>,使容器初始化更加方便

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

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

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

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

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


🌆总结

以上就是关于 C++11『基础新特性』的全部内容了,在本文中首先介绍了 C++11 的背景知识及更新内容,然后介绍了各种常用特性,比如 列表初始化、auto、范围 for 等,这些都是 C++11 中的普通特性,令人眼前一亮的特性将会在后续文章中详解


星辰大海

相关文章推荐

C++ 进阶知识

C++ 哈希的应用【布隆过滤器】

C++ 哈希的应用【位图】

C++【哈希表的完善及封装】

C++【哈希表的模拟实现】

C++【初识哈希】

C++【一棵红黑树封装 set 和 map】

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从替代走向引领,永洪科技迈向全球化

对于数据分析领域而言&#xff0c;这是一个最好的时代。 《全球数字经济白皮书&#xff08;2023年&#xff09;》介绍&#xff0c;2016年-2022年&#xff0c;中国数字经济年均复合增长率为14.2%&#xff0c;数字经济发展增速和规模兼具。随着数字基础实施持续夯实、数字应用不…

接口开放太麻烦?试试阿里云API网关吧

前言 我在多方合作时&#xff0c;系统间的交互是怎么做的&#xff1f;这篇文章中写过一些多方合作时接口的调用规则和例子&#xff0c;然而&#xff0c;接口开放所涉及的安全、权限、监控、流量控制等问题&#xff0c;可不是简简单单就可以解决的&#xff0c;这一般需要专业的…

红队系列-shellcode AV evasion免杀合集

shellcode免杀 一些概念shellcode EDR 了解国内360全家桶360核晶引擎 火绒腾讯电脑管家安全狗金山毒霸瑞星 国外Windwos DefenerKaspersky 卡巴斯基ESET Nod32NortonMcAfeeAVASTAVG科摩多火眼诺顿Symantec小红伞 AV检测方式分类静态扫描引擎特征码扫描识别文件效验和法静态免杀…

媒体软文投放的流程与媒体平台的选择

海内外媒体软文&#xff1a;助力信息传播与品牌建设 在当今数字化时代&#xff0c;企业如何在庞大的信息海洋中脱颖而出&#xff0c;成为品牌建设的领军者&#xff1f;媒体软文投放无疑是一项强大的策略&#xff0c;通过选择合适的平台&#xff0c;精准投放&#xff0c;可以实…

大洋钻探系列之二IODP 342航次是干什么的?(上)

本文简单介绍一下大洋钻探IODP 342航次&#xff0c;从中&#xff0c;我们一窥大洋钻探航次的风采。 IODP342的航次报告在网络上可以下载&#xff0c;英文名字叫《Integrated Ocean Drilling ProgramExpedition 342 Preliminary Report》&#xff0c;航次研究的主要内容是纽芬兰…

学习c#的第九天

C# 可空类型&#xff08;Nullable&#xff09; C# 可空类型&#xff08;Nullable&#xff09; 可空类型允许我们在值类型中包含 null 值&#xff0c;这在处理数据库查询结果或需要表示缺失值的情况时非常有用。 声明一个可空类型的语法如下&#xff1a; < data_type>…

【Python Opencv】图片与视频的操作

文章目录 前言一、opencv图片1.1 读取图像1.2 显示图像1.3 写入图像1.4 示例代码 二、Opencv视频2.1 从相机捕获视频获取摄像头一帧一帧读取显示图片VideoCapture 中的get和set函数示例代码 2.2 从文件播放视频示例代码 2.3 保存视频示例代码 总结 前言 在计算机视觉和图像处理…

蓝桥杯 选择排序

选择排序的思想 选择排序的思想和冒泡排序类似&#xff0c;是每次找出最大的然后直接放到右边对应位置&#xff0c;然后将最 右边这个确定下来&#xff08;而不是一个一个地交换过去&#xff09;。 再来确定第二大的&#xff0c;再确定第三大的… 对于数组a[]&#xff0c;具体…

50个值得关注的生成式AI初创企业【2023】

在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 生成式AI初创公司已成为科技界最新、最强大的参与者&#xff0c;它们利用自然语言处理、机器学习和其他形式的人工智能为各种业务用例生成…

总结MYSQL中VHARCHAR和TEXT

前几天在设计表结构时&#xff0c;针对表中的一个字段使用text还是使用varchar是受到了开发同学的挑战。本篇文章对text和varchar的区别做个总结。 VHARCHAR和TEXT对比 char(n)varchar(n)中括号中n代表字符的个数&#xff0c;并不代表字节个数&#xff0c;所以当使用了中文的…

实战 | 基于卷积神经网络的蘑菇识别微信小程序

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2023.11.13 Last edited: 2023.11.13 导读&#xff1a;其实没啥难的&#xff0c;主要是随手搞了就发出来把&#xff0c;太久没有水过帖子了&…

LCA

定义 最近公共祖先简称 LCA&#xff08;Lowest Common Ancestor&#xff09;。两个节点的最近公共祖先&#xff0c;就是这两个点的公共祖先里面&#xff0c;离根最远的那个。 性质 如果 不为 的祖先并且 不为 的祖先&#xff0c;那么 分别处于 的两棵不同子树中&#…

Python高级语法---Python内存管理机制

文章目录 1. 内存管理基础引用计数2. 垃圾回收机制垃圾回收3. 使用weakref处理循环引用weakref模块总结Python是一种高级编程语言,其内存管理机制高效且用户友好。这篇文章将详细介绍Python的内存管理基础、垃圾回收机制,以及如何使用weakref模块处理循环引用。我们将通过简单…

同为科技(TOWE)主副控智能自动断电桌面PDU插排

在这个快节奏的现代社会&#xff0c;我们越来越需要智能化的产品来帮助我们提高生活质量和工作效率&#xff0c;同时&#xff0c;为各种家用电器及电子设备充电成为不少消费者新的痛点。桌面插排如何高效、安全地管理这些设备&#xff0c;成为了一个亟待解决的问题。同为科技&a…

CopyOnWriteArrayList内存占用过多

目录 一、CopyOnWriteArrayList二、CopyOnWriteArrayList的适用场景三、CopyOnWriteArrayList内存占用过多的解决方法四、CopyOnWriteArrayList.add()源码分析 大家好&#xff0c;我是哪吒。 一、CopyOnWriteArrayList CopyOnWriteArrayList是Java中的一个线程安全的ArrayLis…

负债1320万美元的【思宏集团/Neo-Concep】申请900万美元纳斯达克IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于香港的思宏集团Neo-Concept International Group Holdings Limited(简称&#xff1a;思宏集团&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c…

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(四)

编辑员工和分类模块功能开发 1. 编辑员工1.1 需求分析与设计1.1.1 产品原型1.1.2 接口设计 1.2 代码开发1.2.1 回显员工信息功能1.2.2 修改员工信息功能 1.3 功能测试 2. 分类模块功能开发2.1 需求分析与设计2.1.1 产品原型2.1.2 接口设计2.1.3 表设计 2.2 代码实现2.2.1 Mappe…

ip数据包

数据报文格式 首部 版本&#xff08;Version&#xff09; 版本字段占4bit&#xff0c;通信双方使用的版本必须一致。对于IPv4&#xff0c;字段的值是4。 首部长度&#xff08;Internet Header Length&#xff0c; IHL&#xff09; 占4bit&#xff0c;首部长度说明首部有多少…

Clickhouse学习笔记(13)—— Materialize MySQL引擎

该引擎用于监听 binlog 事件&#xff0c;类似于canal、Maxwell等组件 ClickHouse 20.8.2.3 版本新增加了 MaterializeMySQL 的 database 引擎&#xff0c;该 database 能映射到 MySQL中的某个database &#xff0c;并自动在ClickHouse中创建对应ReplacingMergeTree。 ClickHous…

MPLS VPN详解

了解MPLS VPN之前&#xff0c;要先了解一下MPLS。 了解MPLS之前&#xff0c;先回顾一下基于MAC地址的交换和基于IP地址的路由转发。 &#xff08;上篇主要是介绍基于mac地址的交换、基于IP地址的路由转发、MPLS详解&#xff09; &#xff08;下篇主要是MPLS VPN的网络结构、…