c++11语法特性

c++11

1.c++11发展简介

第一个比较正式的c++标准是1998提出的c++98标准。之后定了5年计划,每5年来一次大更新。在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。 从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多。

2.列表初始化

​ 总结:对于自定义类型,1.可以使用花括号传参直接调用构造;2.也可以用花括号构造initializer_list对象,然后在调用使用initializer_list对象的构造或者赋值;对于内置类型使用花括号直接传参构造;

2.1{}初始化

​ 在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。

即一切皆可以使用花括号初始化,并且可以不写等号。这样就可以支持多参数的隐式类型转换,减少使用匿名对象进行构造;主要是为了支持多参数的构造。

2.2initializer_list

​ 类模板,存放的是常量区数组,不支持写。底层设计是存放了两个const T*指针start(指向开始)和finish(指向最后一个位置的下一个位置),注意不是连续的空间,所以类对象的大小是8。

template<class T> class initializer_list;
//
const int* ptr = { 1,2,3 };//不支持,因为右边会被识别成initializer_list<T>对象,无法进行转换

​ 各种容器都支持initializer_list类对象的构造函数,进行初始化;赋值也支持了initializer_list类对象;

3.声明

3.1auto

​ c++11提供了多种简化声明的方式,尤其是在使用模板时。auto用于定义变量

​ 在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。

3.2decltype

​ 用于声明变量,不需要定义,关键字decltype将变量的类型声明为表达式指定的类型;

​ 还可以声明函数指针类型变量decltype(malloc) pf,或者用来进行模板实例化B<decltype(变量名)>;

​ decltype还可以与lambda表达式配合着使用;

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;F(1, 'a');return 0;
}

3.3nullptr

​ 由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

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

4.范围for

​ 除了原生数组是使用的指针,其他类型被替换成了迭代器

5.STL新变化

5.1新容器

​ c++11新增了array、forward_list、unordered_map、unordered_set这些容器;

​ array唯一的优势就是强制越界检查,较为鸡肋;

​ forward_list只支持了头插头删,不支持尾插尾删,因为尾插,尾删要找前一个位置,效率低,insert和erase也只是支持了当前位置的后一个位置插入删除;真正使用的意义可能就是哈希桶的子结构,但是实现起来并不复杂,所以这个结构也是较为冗余;

在这里插入图片描述

5.2新接口

​ 1.关于迭代器,const版本的迭代器都加了cbegin类似这种风格,较为鸡肋;

2.提供了使用initializer_list对象进行初始化和赋值;

​ 3.还增加了一些个性化接口,如缩容等;

4.所有的容器都提供了emplace系列的接口,涉及到了右值引用和模板的可变参数;好处就是有了较大的性能提升

5.所有的容器都提供了移动构造和移动赋值版本;使得深拷贝的性能提高了90%;

6.右值引用和移动语义

​ const左值对象既可以引用左值属性,又可以引用右值属性,但是不可以修改,而右值引用的出现就是为了可以修改这种具有常性的临时对象,这样就可以支持移动构造,使得平时深拷贝的临时对象或者将亡对象的资源让别的变量获取;

6.1左值引用和右值引用

什么是左值?什么是左值引用?

​ 左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址,一般可以对它赋值,左值可以出现赋值符号的左边或者右边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

​ 常用如:指针变量、解引用指针变量,普通变量,const变量

什么是右值?什么是右值引用?

​ 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址和修改。右值引用就是对右值的引用,给右值取别名。 即都是一些不可以取地址的数据;

​ 常用如:字面常量:10、表达式返回值、函数返回值、临时对象也是右值,对于"xxx",被编译器识别成了首元素的地址,所以可以&“xxx”,即常量字符串是左值;

​ 以前使用的引用都是左值引用,语法上不开空间,取别名;

​ 左值引用:就是给左值取别名,右值引用:就是给右值取别名;

6.2右值引用的使用

​ const&既可以引用左值又可以引用右值,权限的缩小或者平移,即左值引用是可以引用右值的,但是右值引用一般是不可以引用左值的,使用move之后就可以了,但是会带来一些影响;

​ 左值引用存在缺陷,局部对象不能引用返回,即必须是拷贝返回,但是要解决深拷贝的问题,使用移动拷贝(资源只产生了一份),移动拷贝对于浅拷贝没有意义;

​ 一般将内置类型的右值叫做:纯右值,自定义类型的右值叫做:将亡值;

​ 场景一:传值返回;

​ 右值引用使用移动拷贝,将右值的资源拿来,如果是移动赋值将本身的资源交给右值,让它析构,移动构造将自身置为空,即使用移动拷贝比深拷贝代价小;

​ 以前传值返回与传值接收是两次深拷贝,使用移动拷贝之后就变成了深拷贝加移动拷贝;经过编译器优化之后就变成了一次移动拷贝;编译器优化了两次,第一次优化成了一次拷贝构造,第二次优化是将局部变量识别成右值,本来是左值;

对于识别成左值就会走拷贝构造,识别成右值就会走移动构造,被move之后进行构造,就会将被move的值识别成右值

int&&a=10;

​ 场景二:作为参数。

​ list<string>,外界push_back (string对象时)每一个节点的构造都会调用string的深拷贝,如果使用右值引用,进行移动拷贝只使用一个资源,可以很好的利用空间;

​ 移动语义就是利用右值实现移动构造和移动赋值;

7.完美转发forward<T>(t)

​ 模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,即int&&a=move(b),a的属性是左值,move(b)的属性是右值,实际上a开辟了空间可以支持修改;

​ 我们希望能够在传递过程中保持它的左值或者右值的属性,使用完美转发 std::forward<T>(t)在传参的过程中保持了t的原生类型属性。

​ 实参是左值则进行引用折叠;

7.1完美转发的使用场景

​ 有的地方需要使用左值属性如:传参修改,而有的地方需要使用右值属性如:继续多层函数传参实现移动语义;

​ 右值引用右值,但是需要能够对引用的值进行修改或者给左值函数进行传参,所以默认保证了右值引用变量是左值属性;如果右值引用变量作为参数需要调用移动构造,但是本身是左值属性的,这是就需要使用完美转发,保持右值属性,才能调用到移动构造,否则调用的就是深拷贝;

​ 总结:c++11之后使用右值引用,类模板里面的函数就需要写成函数模板使用万能引用,每一个要传递的值使用forward<T>(变量),如果仅仅是当前使用则不需要加完美转发;

8.lambda表达式

​ 用来替代函数指针,甚至是某些场景下用来替代仿函数;

​ lambda是一个匿名函数的对象,用固定的语法就不需要写专门的仿函数类再实例化对象了;

​ 最好的使用场景就是和线程进行配合;

vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; });
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price > g2._price; });
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate < g2._evaluate; });
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate > g2._evaluate; });

8.1对比不同的函数可调用对象

1.函数指针,能不用就不用,因为使用起来较为复杂

​ 返回值类型(*函数指针变量名)(参数)

2.仿函数,可以使用,较为麻烦的点就是,每次需要时都需要写一个类,并且使用时需要实例化对象,使用时较为"“重”;

​ 类 重载operator(), 对象可以像函数一样使用;

3.lambda表达式,是一个匿名的函数对象

​ 直接在函数的内部使用;

8.2lambda表达式语法

lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement }

​ []:捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用;

​ ():参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略;

​ mutable :默认情况下,lambda函数总是一个const函数,mutable可以取消其常量

性。使用该修饰符时,参数列表不可省略(即使参数为空)。主要的使用场景就是捕获列表的拷贝值可以修改;

​ ->:返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。一般都不需要写返回值,除非进行强制类型转换;

​ {}:函数体:在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

​ 在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

​ 对于局部域内,想要使用lambda外部的对象,但是又不通过传参的方式使用,需要将其捕获到捕获列表,而全局域的函数和对象是可以使用的;

8.2.1捕获列表的使用方式

​ [var]:表示值传递方式捕捉变量var,是一种拷贝 ;

​ [=]:表示值传递方式捕获所有父作用域中的变量(包括this) ;

​ [&var]:表示引用传递捕捉变量var ,包括const引用,注意并不是以前的取地址;

​ [&]:表示引用传递捕捉所有父作用域中的变量(包括this),包括const引用 ;

​ [this]:表示值传递方式捕捉当前的this指针 ;

可以组合使用如:[&,a],[=,a],前面是默认设置,后面是显式捕获;

注意:

a. 父作用域指包含lambda函数的语句块 ;

b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 ,[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量 ;

c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复 ;

d. 在块作用域以外的lambda函数捕捉列表必须为空;

e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错,即在全局定义时,捕获列表必须为空;

f. lambda表达式之间不能相互赋值,即使看起来类型相同,但是生成的类是不一样的 ;

8.3底层实现

​ lambda表达式的底层就是仿函数;类型时lambda+uuid字符串,uuid时通用唯一识别码,是使用一种算法生成的一个字符串;

​ 其实捕捉列表就是调用了构造,将捕获的变量都生成了默认const成员变量,mutable之后就没有加const修饰;

9.模板可变参数

​ 总结一下:1.函数包的展开方式需要嵌套调用其他函数来完成;2.最大的价值就是作为中间函数一次性接收所有参数,一次性传递所有参数;

​ printf系列函数就是使用了可变参数;可变模板参数不是使用数组的方式实现的;

​ C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}
//查看参数包里面参数的个数
sizeof...(args);

​ 上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数,所以我们的用一些奇招来一一获取参数包的值。

9.1递归方式展开参数包

​ 递归编译,最后形成的结果还是按照递归编译的顺序来的;

// 递归终止函数
template <class T>
void ShowList(const T& t)
{cout << t << endl;
}
//对于结束函数可以写一个无参的非函数模板,只需要函数名相同即可
void ShowList()
{cout << endl;
}
// 展开函数
template <class T, class ...Args>
void ShowList(T value, Args... args)
{cout << value <<" ";ShowList(args...);//这样传递的就是所有的参数
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

9.2逗号表达式展开参数包

​ 逗号表达式执行的结果是最后一部分,即借用数组的初始化来完成展开;

template <class T>
void PrintArg(T t)
{cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args)
{int arr[] = { (PrintArg(args)/*此处是传递的一个值*/, 1)... };//后面的...是其他参数,本质上使用的是多参数的构造;cout << endl;
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

9.3使用子函数的方式展开参数包

template <class T>
void _ShowList(const T& t)
{cout << t << endl;
}
template <class T, class ...Args>
void ShowList(T value, Args... args)
{cout << value <<" ";ShowList(args...);
}
template <class ...Args>
void ShowList(Args... args)
{_ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

10.包装器

10.1fuction

​ function包装器,也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。;

​ 有了包装器之后就可以统一类型可以用于,将函数调用对象存放到容器中,这样使用调用对象时就可以去容器中进行查找;

​ 包装器解决了调用对象的类型问题,统一了调用对象的类型,使得容器中存放的都是类模板实例化之后的包装器类型;

std::function在头文件<functional>
// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;//function<返回值(可变参数列表)>
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

​ 存在一个指令对应一个动作的场景,即使用map<string,包装器实例化出来的对象>;

10.2bind

​ std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器)**,**接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

​ 即bind是用来调整参数的(数量和参数方面的);

​ placeholder(占位符),placeholders命名空间内存放了_n参数,按被包装函数的参数列表顺序,分别代表着第1个参数…,调整_n顺序,则可以调整参数顺序;

template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2) 
template <class Ret/*函数返回值调整*/, class Fn/*可调用对象*/, class... Args/*调用对象的参数包*/>
/* unspecified */ bind (Fn&& fn, Args&&... args);
double ala(int x, int y,double rate)
{return (x + y) / rate;
}
function<double(int,int)> f1 =  bind(ala,placeholders::_1,placeholders::_2,4.3);
//1.不写_2 _3是因为按照的是函数的实参来的,固定的数就不参与排序
//2.绑定类的静态员函数要加类名::,如果是普通成员函数需要&Sub::sub,即在类名前面加&,但是要注意其实普通成员函数还有隐含的this指针,所以要定义一个对象,然后把对象地址传入,或者直接传对象/匿名对象;
function<double(int,int)> f1 =  bind(ala,4.3,placeholders::_1,placeholders::_2);
10.2.1bind的底层实现

​ 和lambda类似,底层实现是一个仿函数,传入对象是用对象调用函数,传入对象地址是用指针进行调用;

11.emplace/emplace_back函数

​ 与push_back效率其实相差不大,真正的意义是对于多层复杂结构可以将参数包传到最底层,调用构造,而push_back则会是用对象调用拷贝;

emplace_back(make_pair(1,2));//右值调用移动语义拷贝构造
emplace_back({1,2});//右值调用移动语义构造
emplace_back(1,2);//直接将参数包传递给构造函数构造

在这里插入图片描述

12.新的类功能

12.1默认成员函数

​ c++11类一共有8个默认成员函数,增加了移动构造和移动赋值;

对于这两个函数,如果是深拷贝则需要自己实现移动构造和移动赋值,如果是浅拷贝编译器生成的默认拷贝构造即可满足要求;

对于编译器自动生成的移动构造:

​ 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个(其实需要自己实现析构,拷贝构造,拷贝赋值重载,那么说明这个类的对象需要在堆上开空间,是一个深拷贝的对象)。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝(浅拷贝),自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。

对于编译器自动生成的移动赋值:

​ 默认移动赋值跟与默认移动构造完全类似;

强制生成默认函数的关键字default

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

Person(Person&& p) = default;

禁止生成默认函数的关键字delete:

​ 如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只是声明补丁而已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

Person(const Person&p) = delete;

12.2类成员变量初始化

​ C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化;

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

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

相关文章

RabbitMQ 模拟实现【三】:存储设计

文章目录 数据库设计SQLite配置数据库实现 数据库关于哈希表等复杂类的存储启动数据库 文件设计消息持久化消息属性格式核心方法消息序列化消息文件回收 统一硬盘存储管理内存存储管理线程安全数据结构实现 数据库设计 数据库主要存储交换机、队列、绑定 SQLite 此处考虑的是…

完整的通过git命令框和windows窗口将本地文件上传到gitee远程仓库流程步骤

1.下载git 这个网站搜索git官方&#xff0c;去下载就行了 2.打开git安装后的Git Bash命令框 3.在Git Bash命令框设置一下要远程链接的gitee账号 git config --global user.name “名字”Git config --global user.email “邮箱” 4.查看一下账号设置 git config --global -…

Chitosan-PEG-DSPE 壳聚糖修聚乙二醇磷脂 DSPE-PEG-Chitosan

产品简称&#xff1a;DSPE-PEG-Chitosan、Chitosan-PEG-DSPE、DSPE-PEG-CS、CS-PEG-DSPE 产品中文名称&#xff1a;壳聚糖-聚乙二醇-磷脂、磷脂-聚乙二醇-壳聚糖 分子量&#xff1a;可以根据要求定制 保存条件&#xff1a; -20干燥保存 有效期&#xff1a; 一年 纯度&…

创建SpringCloudGateWay

创建SpringCloudGateWay 本案例基于尚硅谷《谷粒商城》项目&#xff0c;视频27 创建测试API网关 1、创建module 2、引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:x…

C++进阶--mep和set的模拟实现

红黑树链接入口 底层容器 模拟实现set和map时常用的底层容器是红黑树。 红黑树是一种自平衡的搜索二叉树&#xff0c;通过对节点进行颜色标记来保持平衡。 在模拟实现set和map时&#xff0c;可以使用红黑树来按照元素的大小自动排序&#xff0c;并且保持插入和删除操作的高效…

Set cancelled by MemoryScratchSinkOperator

Bug信息 Caused by: com.starrocks.connector.spark.exception.StarrocksInternalException: StarRocks server StarRocks BE{host=10.9.14.39, port=9060} internal failed, status code [CANCELLED] error message is [Set cancelled by MemoryScratchSinkOperator]Bug产生的…

微信名【无感】的同学,你还好吗?

今天遇到个选择了微信一对一服务的同学&#xff0c;问Python问题&#xff0c;问题比较简单。 回答完问题&#xff0c;我就说了一句&#xff1a;问题比较简单&#xff0c;随意打赏一个红包就行了。 然后我就被拉黑了&#xff0c;然后我的解答问题&#xff0c;收到了一堆投诉&…

深入解析Java中锁机制以及底层原理

一、概述 1.1 背景 概念&#xff1a;锁是多线程编程中的机制&#xff0c;用于控制对共享资源的访问。可以防止多个线程同时修改或读取共享资源&#xff0c;从而保证线程安全。 作用&#xff1a;锁用于实现线程间的互斥和协调&#xff0c;确保在多线程环境下对共享资源的访问顺…

Flutter开发入门——Widget和常用组件

1.什么是Widget&#xff1f; 在Flutter中几乎所有的对象都是一个 widget 。与原生开发中“控件”不同的是&#xff0c;Flutter 中的 widget 的概念更广泛&#xff0c;它不仅可以表示UI元素&#xff0c;也可以表示一些功能性的组件如&#xff1a;用于手势检测的 GestureDetecto…

spring中事务失效的场景有哪些?

异常捕获处理 在方法中已经将异常捕获处理掉并没有抛出。 事务只有捕捉到了抛出的异常才可以进行处理&#xff0c;如果有异常业务中直接捕获处理掉没有抛出&#xff0c;事务是无法感知到的。 解决&#xff1a;在catch块throw抛出异常。 抛出检查异常 spring默认只会回滚非检…

ChatGPT浪潮来袭!谁先掌握,谁将领先!

任正非在接受采访时说 今后职场上只有两种人&#xff0c; 一种是熟练使用AI的人&#xff0c; 另一种是创造AI工具的人。 虽然这个现实听起来有些夸张的残酷&#xff0c; 但这就是我们必须面对的事实 &#x1f4c6; 对于我们普通人来说&#xff0c;我们需要努力成为能够掌握…

基于STM32的智慧农业管理系统设计与实现

文章目录 一、前言1.1 项目介绍【1】项目功能【2】设计实现的功能【3】项目硬件模块组成 1.2 设计思路1.3 传感器功能介绍1.4 开发工具的选择 二、EMQX开源MQTT服务器框架三、购买ECS云服务器3.1 登录官网3.2 购买ECS服务器3.3 配置安全组3.4 安装FinalShell3.5 远程登录到云服…

xsslabs靶场通关(持续更新)

文章目录 前言一、level1思路实现 二、levle2思路 三、level3思路实现 四、level4思路实现 五、level5思路实现 六、level6思路实现 七、level7思路实现 八、level8思路实现 九、level9思路实现 前言 本篇文章将介绍在xsslabs这个靶场&#xff08;在不知道源码的前提下&#x…

Linux从0到1——Linux环境基础开发工具的使用(上)

Linux从0到1——Linux环境基础开发工具的使用&#xff08;上&#xff09; 1. Linux软件包管理器yum1.1 yum介绍1.2 用yum来下载软件1.3 更新yum源 2. Linux编辑器&#xff1a;vi/vim2.1 vim的基本概念2.2 vim的基本操作2.3 vim正常模式命令集2.4 vim底行模式命令集2.5 视图模式…

Java初阶数据结构队列的实现

1.队列的概念 1.队列就是相当于排队打饭 2.在排队的时候就有一个队头一个队尾。 3.从队尾进对头出 4.所以他的特点就是先进先出 所以我们可以用链表来实现 单链表实现要队尾进队头出{要有last 尾插头删} 双向链表实现效率高&#xff1a;不管从哪个地方当作队列都是可以的&…

OpenMP 编程模型

OpenMP 内存模型 共享内存模型&#xff1a; OpenMP 专为多处理器/核心、共享内存机器设计&#xff0c;底层架构可以是共享内存UMA或NUM OpenMP 执行模型 基于线程的并行&#xff1a; OpenMP 程序基于多线程来实现并行&#xff0c; 线程是操作系统可以调度的最小执行单元。 …

react 综合题-旧版

一、组件基础 1. React 事件机制 javascript 复制代码<div onClick{this.handleClick.bind(this)}>点我</div> React并不是将click事件绑定到了div的真实DOM上&#xff0c;而是在document处监听了所有的事件&#xff0c;当事件发生并且冒泡到document处的时候&a…

Facebook:连接世界的社交巨人

在当今数字化时代&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;扮演着连接世界的重要角色。它不仅仅是一个社交网站&#xff0c;更是一个数字化的社交生态系统&#xff0c;影响着全球数十亿用户的生活和交流方式。本文将深入探讨Facebook的起源、用户规模和…

uniapp——第1篇:基于vue语法的、比原生开发屌的小程序开发

前提&#xff0c;建议先学会前端几大基础&#xff1a;HTML、CSS、JS、Ajax&#xff0c;还有一定要会Vue!&#xff08;Vue2\Vue3&#xff09;都要会&#xff01;&#xff01;&#xff01;不然不好懂 博主作为大二前端小白&#xff0c;刚刚接触前端微信小程序开发时选择的是基于“…

electron + vtkjs加载模型异常,界面显示类似于图片加载失败的图标

electron vtkjs加载模型显示异常&#xff0c;类似于图片加载失败的效果&#xff0c;如上图。 electron开发版本&#xff1a;13。 解决方法&#xff1a;升级electron版本号。 注意&#xff1a;win7最高兼容electron 22版本。