当前位置: 首页 > news >正文

【C++】C++11的新特性(上)

引入 

   C++11作为C++标准的一个重要版本,引入了许多令人振奋的新特性,极大地丰富了这门编程语言的功能和表达能力。本章将为您介绍C++11的一些主要变化和改进,为接下来的章节铺垫。

  

文章目录

引入

一、列表初始化

1、1 {} 初始化

1、2 std::initializer_list的介绍

二、声明

2、1 auto关键字的引入

2、2 decltype关键字

2、3 nullptr

三、智能指针

四、范围for

五、STL中一些变化

5、1 新容器

5、2 新接口

六、右值引用和移动语义

6、1 左值引用和右值引用

6、1、1 左值与左值引用 

6、1、2 右值与右值引用

6、2 左值引用与右值引用比较

6、3 右值引用的使用场景与意义

6、3、1 移动构造

6、3、2 移动赋值

七、总结


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:C++ 👀

💥 标题:C++11 💥

❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

一、列表初始化

1、1 {} 初始化

  在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:

struct Point
{int _x;int _y;
};
int main()
{int array1[] = { 1, 2, 3, 4, 5 };int array2[5] = { 0 };Point p = { 1, 2 };return 0;
}

  在C++11中,引入了列表初始化的概念,允许我们使用花括号来初始化各种类型的对象,使其可用于所有的内置类型和用户自定义的类型,都可以使用统一的初始化语法,从而减少了初始化的歧义性和错误。 使用初始化列表时,可添加等号(=),也可不添加。具体如下:

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()
{int x1 = 1;int x2 = { 2 };int x3 { 2 };// 都是在调用构造函数Date d1(2022, 11, 22);Date d2 = {2022, 11, 11}; Date d3{ 2022, 11, 11 };return 0;
}

  我们发现,C++11列表初始化允许我们使用花括号来初始化各种类型的对象后,可能会在某些情况下带来一些方便,但实际上看起来还是有一点不适应的。

1、2 std::initializer_list的介绍

 std::initializer_list 是 C++11 标准库中引入的一个特殊容器,它用于方便地初始化数据。它允许我们在列表初始化(也称为花括号初始化)的情况下,以逗号分隔的值列表的形式传递一组元素。

  使用 std::initializer_list 可以将一组值作为参数传递给函数或构造函数,从而简化代码的编写,并提高可读性。它的主要作用是用于表示一个不可修改的序列,类似于数组或容器,但没有提供像容器操作那样丰富的接口。

下面是 sstd::initializer_list 的主要特点和用法:

  1. 定义和声明:std::initializer_list 是一个模板类,位于 <initializer_list> 头文件中。可以通过以下语法来声明并初始化一个 std::initializer_list 对象:

    std::initializer_list<T> list = {value1, value2, ...};
  2. 使用范围:std::initializer_list 可以用于任何需要一组值作为参数的上下文中,例如函数参数、构造函数参数等。

  3. 迭代器和大小:std::initializer_list 提供了类似容器的迭代器和大小函数,可以使用 begin()end() 来获取迭代器,size() 来获取序列的大小。

  4. 元素访问:std::initializer_list 并不提供随机访问元素的功能,只能顺序遍历元素。可以使用 std::initializer_list 的迭代器或范围-based for 循环来访问元素。

  具体我们可结合如下实例理解:

int main()
{// 调用支持list (initializer_list<value_type> il)类似这样的构造函数vector<int> v1 = { 1, 2, 3, 4, 5, 6 };vector<int> v2{ 1, 2, 3, 4, 5, 6 };list<int> lt1 = { 1, 2, 3, 4, 5, 6 };list<int> lt2{ 1, 2, 3, 4, 5, 6 };auto x = { 1, 2, 3, 4, 5, 6 };cout << typeid(x).name() << endl;vector<Date> v4 = { { 2022, 1, 1 }, {2022, 11, 11} };string s1 = "11111";// 构造map<string, string> dict = { { "sort", "排序" }, { "insert", "插入" } };// 赋值重载initializer_list<pair<const string, string>> kvil = { { "left", "左边" }, { "left", "左边" } };dict = kvil;return 0;
}

  我们先看一下运行结果:

  同时我们再看一下C++的标准库的介绍文档:

二、声明

2、1 auto关键字的引入

  C++11引入了 auto 关键字,允许变量的类型根据初始化表达式进行自动推导。这种类型推导机制不仅简化了代码书写,还减少了代码中的重复信息,提高了代码的可读性和维护性。

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

int main()
{int i = 10;auto p = &i;auto pf = strcpy;cout << typeid(p).name() << endl;  // int *cout << typeid(pf).name() << endl; // char * (__cdecl*)(char *,char const *) 函数指针map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };//如下auto的作用体现//map<string, string>::iterator it = dict.begin();auto it = dict.begin();return 0;
}

 auto关键字可以方便地简化代码,尤其是当变量类型较为复杂或使用模板时。它可以更灵活地适应不同的场景,并且减少了编写冗长类型名称的工作。

2、2 decltype关键字

  除了 auto 关键字外,C++11还引入了 decltype 关键字。decltype关键字则用于获取表达式的类型,而不是进行类型推导。它主要用于在编译时获取表达式的静态类型信息,并且保留了const、引用修饰符等特性。

  有些同学可能会感觉 auto 和 decltype 非常的相似。其实他们是有所区别的,具体看如下代码:

int main()
{int x = 10;// typeid拿到只是类型的字符串,不能用这个再去定义对象什么的//typeid(x).name() y = 20;  错误// decltype(x) intdecltype(x) y1 = 20.22;auto y2 = 20.22;cout << y1 << endl;cout << y2 << endl;return 0;
}

  运行结果如下图:

2、3 nullptr

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

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

三、智能指针

  后面会专门对智能指针进行详细解释,此处就不再过多解释。

四、范围for

  C++11引入了范围for循环(Range-based for loop),可以更简洁地遍历容器或者其它可迭代对象的元素。具体使用方式是:“for (type variable : range)”。

  范围for循环的底层原理是通过迭代器(iterator)实现的。迭代器是访问容器内元素的一种方式,通过指向容器中的特定位置来遍历元素。范围for循环会自动遍历整个容器中的元素,并使用迭代器实现循环。

下面是范围for循环使用与底层原理的详解:

  1. 使用方式:
    • 针对容器:对于容器类型(比如vector、list等),范围for循环按顺序遍历容器中的每个元素,将每个元素赋值给变量,直到遍历完所有元素。
    • 针对数组:对于数组类型,范围for循环也能正常工作,类似于按顺序访问数组中的每个元素。
    • 自定义类型:如果要对自定义类型使用范围for循环,需要定义相应的迭代器接口或者提供begin()和end()成员函数,以便定义迭代的开始和结束位置。

示例代码如下:

std::vector<int> vec = {1, 2, 3, 4, 5};
for (int num : vec) {std::cout << num << " ";
}
// 输出:1 2 3 4 5int arr[] = {6, 7, 8, 9, 10};
for (int num : arr) {std::cout << num << " ";
}
// 输出:6 7 8 9 10
  1. 底层原理: 范围for循环的底层原理是通过使用迭代器实现的。迭代器是遍历容器或者其它可迭代对象的一种通用方式,提供了对元素的访问和操作。

    范围for循环的执行过程如下:

    • 对于容器类型,编译器会自动调用容器的begin()和end()成员函数获取容器的起始位置和结束位置的迭代器。
    • 对于数组类型,编译器将数组名转换为指向数组首元素的指针作为起始位置,以及指向数组最后一个元素的下一个位置的指针作为结束位置的迭代器。
    • 循环开始时,将起始位置的迭代器赋值给临时变量,然后判断迭代器是否达到结束位置,如果未达到,则执行循环体内的代码。
    • 每次循环迭代时,将迭代器指向的元素赋给循环变量,并使迭代器前进到下一个位置。
    • 直到迭代器达到结束位置,循环停止。

  范围for循环的引入简化了代码编写,使得遍历容器等可迭代对象更加方便和易读。

五、STL中一些变化

5、1 新容器

  C++11STL中引入了一些新的容器,如下图:

  C语言中的数组和C++11中的array是两种不同的数据类型,它们在以下几个方面存在一些对比和区别:

  1. 类型安全性:

    • C语言中的数组没有类型安全性检查,可以存储任意类型的数据。这就意味着您可以将一个元素类型不匹配的值赋给数组,这可能导致不可预测的结果或者错误。
    • C++11中的array是一个模板类,它对数组的类型进行了严格控制。只能存储指定类型的元素,当我们尝试存储不匹配的类型时,会在编译过程中产生错误,提供了更好的类型安全性。
  2. 大小确定性:

    • C语言中的数组在创建时需要显式指定大小,并且在使用时无法动态改变大小。这意味着数组长度是固定的,不能根据需求进行扩展或收缩。
    • C++11中的array也需要在创建时指定大小,但它提供了size()和max_size()等成员函数来获取数组的大小信息。同时,由于C++的特性,您可以使用动态数组(如vector)来代替array,动态数组具备灵活调整大小的能力。
  3. 内存管理:

    • C语言中的数组通过指针实现,其内存管理需要手动进行。数组的声明不会自动分配内存空间,需要使用malloc()或者calloc()等函数进行显式的内存分配和释放操作。
    • C++11中的array作为一个容器类,它在栈上分配内存,并在其作用域结束时自动释放。无需显式调用释放内存函数,这样更方便地管理和避免内存泄漏。
  4. 拷贝行为:

    • C语言中的数组不能直接进行拷贝,只能通过遍历数组元素进行手动赋值或者使用memcpy()函数来实现数组拷贝。
    • C++11中的array可以进行拷贝和移动操作,支持复制构造函数和赋值操作符的使用。

  forward_list 底层就是单链表。重点是unordered_map和unordered_set,其他的大家了解一下即可。

5、2 新接口

  如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的。比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。
  实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本:rempalce_back/emplace。下面我们会详细解释这些接口。

六、右值引用和移动语义

6、1 左值引用和右值引用

  传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

6、1、1 左值与左值引用 

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

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

  下面详细解释左值和左值引用:

  1. 左值:

    • 左值可以表示具有名称的变量、对象或数据成员,例如:int a = 10;、int array[10];、std::string str = "Hello";
    • 左值可以出现在赋值语句的左边或右边,例如:a = 20;、int b = a;;
    • 对一个左值进行取地址操作(&)时,可以获取其在内存中的位置;
    • 左值有持久性,意味着它们在表达式执行完后仍然存在。
  2. 左值引用:

    • 左值引用是使用符号“&”声明的引用类型,例如:int& ref = a;;
    • 左值引用可以将一个左值绑定到引用变量上,并通过引用直接访问绑定的左值;
    • 通过修改引用变量的值,也会影响所绑定的左值;
    • 左值引用可以作为函数的参数,使函数能够修改传递给它的变量的值;
    • 引用本身并不占用内存,它只是对绑定的左值进行别名。
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;
}

6、1、2 右值与右值引用

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

  右值引用(Rvalue Reference)是一种新的引用类型,用于绑定到右值上。它的语法是在类型前面添加两个连续的“&”符号,例如int&&。右值引用可以延长右值的生命周期,也可以让我们知道一个表达式是右值。

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

   需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用,是不是感觉很神奇,这个了解一下实际中右值引用的使用场景并不在于此,这个特性也不重要。

int main()
{double x = 1.1, y = 2.2;int&& rr1 = 10;const double&& rr2 = x + y;rr1 = 20;rr2 = 5.5; // 报错return 0;
}

6、2 左值引用与右值引用比较

  左值引用总结:

  • 左值引用只能引用左值,不能引用右值。
  • 但是const左值引用既可引用左值,也可引用右值。

  右值引用总结:

  • 右值引用只能右值,不能引用左值。
  • 但是右值引用可以move以后的左值。

  具体我们可结合如下代码对左值引用和右值引用进行对比理解:

int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;  // 错误// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}

  std::move是一个函数模板,定义在<utility>头文件中。它接受一个对象作为参数,并将其转换为右值引用。调用std::move后,原始对象的值仍然有效,但不能再保证其状态的有效性。std::move用于标记一个对象为可移动的,并将其传递给需要右值引用参数的函数,以实现资源的移动而不是复制。 

6、3 右值引用的使用场景与意义

6、3、1 移动构造

  我们知道,引用就是别名,其价值是为了减少拷贝。但是左值引用可以解决一些问题,同时也会遇到一些特殊情况解决不了拷贝的问题,具体如下:

  1. 做参数:a、减少拷贝,提高效率。b、做输出型参数,减少拷贝。
  2. 做返回值:a、引用返回可减少拷贝,提高效率。b、引用返回,可对返回值进行修改。

  但是并不是任何情况下返回值都可以是引用返回的。当返回值是临时变量(出了函数的作用域就销毁),就不可以作为引用返回。此时拷贝就是必不可少的。如下场景:

  这种情况就是避免不了需要进行拷贝,如下图:

  大部分编译器会对上述情况进行优化,不会产生中间的临时变量。直接使用str拷贝构造ret。那有没有很好的办法解决拷贝这种情况呢? 

  当然,我们也可以选择使用输出型参数,但是并不符合我们的使用习惯。具体如下:

   在C++11中,引入了移动构造。对比拷贝构造具体代码如下:

		// 移动构造string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 资源转移" << endl;swap(s);  // 资源转移}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 拷贝构造(深拷贝)" << endl;//string tmp(s._str);//swap(s);_str = new char[s._capacity+1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}

  因为上述的 str 出了作用域就会销毁,我们将它视为将亡值,也就是右值。在既有拷贝构造和移动构造的情况下,编译器会匹配最移动构造。因为编译器会匹配最适合的参数。那么这里就不会采用拷贝构造了,而是选择移动构造。

  大部分编译器也会对上述进行优化。直接将 str 的资源转移到 ret 中。对比拷贝构造,我们能够明显的感觉出来,移动构造并没有进行申请资源,而是直接将将亡值的资源进行转移。移动构造减少了资源的申请和拷贝,提高了效率

6、3、2 移动赋值

  移动赋值与移动构造的原理大同小异。具体情况如下:

  上图的情况必须要进行拷贝构造和拷贝赋值。在C++11中引入移动构造后,同时也引入的移动赋值,对比移动复制和拷贝赋值具体代码如下:

        // 拷贝赋值string& operator=(const string& s){cout << "string& operator=(string s) -- 拷贝赋值(深拷贝)" << endl;string tmp(s);swap(tmp);return *this;}// 移动赋值string& operator=(string&& s){cout << "string& operator=(string s) -- 移动赋值(资源移动)" << endl;swap(s);return *this;}

  同样,这里的 str 会被识别成将亡值(右值),不会再调用拷贝构造和拷贝赋值。会调用移动构造和移动复制。移动构造和移动复制都是对右值的资源进行移动转移,减少了资源的申请和拷贝,从而提高效率。

  移动构造和移动赋值操作相对于拷贝构造和拷贝赋值操作的优点有以下几个方面:

  1. 性能更高:移动操作能够直接将资源(比如堆上的内存)从一个对象转移到另一个对象,而无需进行复制和销毁。这样可以消除额外的内存分配和释放开销,提高程序的性能。

  2. 减少内存拷贝:移动操作通过转移资源的所有权,避免了不必要的内存拷贝过程。对于大型对象或频繁进行内存操作的情况下,移动操作可以显著减少内存拷贝的次数,提高程序的效率。

  3. 资源管理效率:移动操作使得资源管理更加高效。在移动语义中,资源的所有权转移给了目标对象,源对象则不再拥有该资源。这意味着在移动后,源对象不再需要释放或删除资源。这样一来,在一些场景下可以避免重复释放资源或导致资源泄漏的问题。

  4. 容器的性能提升:使用移动构造和移动赋值可以有效提高容器操作(比如动态数组、动态字符串等)的性能。很多标准库容器都提供了移动语义的支持,通过移动操作,可以快速将对象移入或移出容器,而不会进行额外的拷贝操作。

  需要注意的是,移动操作通常适用于临时对象、将要被销毁的对象以及右值引用的情况下,而拷贝操作适用于需要保留原始对象的情况。对于用户自定义的类,为了充分利用移动操作,通常需要显式实现移动构造函数和移动赋值运算符,并确保正确处理资源的转移和释放。

七、总结

  由于C++11更新的重要内且常用容较多,就分为两篇内容进行详解。本篇内容的细节较多,重点在于右值引用和移动语义。下篇文章内容依然较多且为重要。本篇文章的讲解就到这里,感谢阅读ovo~

相关文章:

【C++】C++11的新特性(上)

引入 C11作为C标准的一个重要版本&#xff0c;引入了许多令人振奋的新特性&#xff0c;极大地丰富了这门编程语言的功能和表达能力。本章将为您介绍C11的一些主要变化和改进&#xff0c;为接下来的章节铺垫。 文章目录 引入 一、列表初始化 1、1 {} 初始化 1、2 std::initiali…...

ubuntu学习(四)----文件写入操作编程

1、write函数的详解 ssize_t write(int fd,const void*buf,size_t count); 参数说明&#xff1a; fd:是文件描述符&#xff08;write所对应的是写&#xff0c;即就是1&#xff09; buf:通常是一个字符串&#xff0c;需要写入的字符串 count&#xff1a;是每次写入的字节数…...

如何解决MySQL中的套接字错误

MySQL通过使用** socket文件**来管理到数据库服务器的连接&#xff0c;socket文件是一种特殊的文件&#xff0c;可以促进不同进程之间的通信。MySQL服务器的套接字文件名为mysqld.sock&#xff0c;在Ubuntu系统中&#xff0c;它通常存储在/var/run/mysqld/目录中。该文件由MySQ…...

socket

Socket是一种用于网络通信的编程接口&#xff0c;它提供了在计算机网络中进行数据传输的方法。通过Socket&#xff0c;可以在不同主机之间建立网络连接&#xff0c;并通过发送和接收数据来进行通信。在C语言中&#xff0c;可以使用Socket函数库&#xff08;如BSD Socket或Winso…...

Python数据分析实战-判断一组序列(列表)的变化趋势(附源码和实现效果)

实现功能 判断一组序列&#xff08;列表&#xff09;的变化趋势 实现代码 from sklearn.linear_model import LinearRegression import numpy as np # 计算相邻两个数之间的差值的均值&#xff0c;并判断变化趋势。 def trend(lst):diff [lst[i1] - lst[i] for i in range(…...

Spring与MyBatis集成 AOP整合PageHelper插件

目录 1.什么是集成&#xff1f; 2.Spring与MyBatis集成 3.Spring与MyBatis集成的基本配置 4.AOP整合PageHelper插件 1.什么是集成&#xff1f; 集成是指将不同的组件、框架或系统整合到一起&#xff0c;使它们可以协同工作、相互调用、共享资源等。通过集成&#xff0c;可以…...

[Android 四大组件] --- BroadcastReceiver

1 BroadcastReceiver是什么 BroadcastReceiver&#xff08;广播接收器&#xff09;即广播&#xff0c;是一个全局的监听器。 Android 广播分为两个角色&#xff1a;广播发送者、广播接受者。 2 广播类型 广播按照类型分为两种&#xff0c;一种是全局广播&#xff0c;另一种…...

<C++> STL_容器适配器

1.容器适配器 适配器是一种设计模式&#xff0c;该种模式是将一个类的接口转换成客户希望的另外一个接口。 容器适配器是STL中的一种重要组件&#xff0c;用于提供不同的数据结构接口&#xff0c;以满足特定的需求和限制。容器适配器是基于其他STL容器构建的&#xff0c;通过…...

【25考研】- 整体规划及高数一起步

【25考研】- 整体规划及高数一起步 一、整体规划二、专业课870计算机应用基础参考网上考研学长学姐&#xff1a; 三、高数一典型题目、易错点及常用结论&#xff08;一&#xff09;典型题目&#xff08;二&#xff09;易错点&#xff08;三&#xff09;常用结论1.令tarctanx, 则…...

【Unity】常见的角色移动旋转

在Unity 3D游戏引擎中&#xff0c;可以使用不同的方式对物体进行旋转。以下是几种常见的旋转方式&#xff1a; 欧拉角&#xff08;Euler Angles&#xff09;&#xff1a;欧拉角是一种常用的旋转表示方法&#xff0c;通过绕物体的 X、Y 和 Z 轴的旋转角度来描述物体的旋转。在Un…...

今天的小结

1、冒泡排序 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它重复地遍历待排序的元素列表&#xff0c;比较相邻的元素并交换它们的位置&#xff0c;直到整个列表排序完成。冒泡排序的基本思想是通过不断交换相邻元素&#xff0c;将最大&#…...

了解 Socks 协议:它的过去、现在与未来

在网络世界的江湖中&#xff0c;有一名叫做 Socks 协议的高手&#xff0c;它凭借着一招“代理”绝技&#xff0c;在网络安全领域独步天下。今天&#xff0c;就让我们来了解一下这位神秘高手的过去、现在和未来。 在过去&#xff0c;互联网世界的江湖可谓是风起云涌&#xff0c;…...

小谈静态类和单例模式

静态类&#xff08;Static Class&#xff09;和单例&#xff08;Singleton&#xff09;都是在编程中用于实现特定类型的设计模式或代码组织方式。它们在不同的情境下有不同的用途和特点。 静态类&#xff08;Static Class&#xff09; 静态类是一种类&#xff0c;它的方法和属…...

​LeetCode解法汇总823. 带因子的二叉树

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给出一个含…...

TypeScript的变量声明的各种方式

TypeScript是一种静态类型的JavaScript超集&#xff0c;它为JavaScript代码提供了类型检查和更好的代码组织结构。在TypeScript中&#xff0c;变量声明是非常重要的&#xff0c;因为它们定义了变量的类型和范围。本文将详细介绍TypeScript的变量声明&#xff0c;并通过代码案例…...

c++ lambda

Lambda Lambda 表达式一般用于定义匿名函数&#xff0c;使得代码更加灵活简洁&#xff0c;优点&#xff1a; 声明式编程风格&#xff1a;就地匿名定义目标函数或函数对象&#xff0c;不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序&#xff0c;好的可读性和可…...

泊松回归和地理加权泊松回归

01 泊松回归 泊松回归(Poisson Regression)是一种广义线性模型,用于建立离散型响应变量(计数数据)与一个或多个预测变量之间的关系。它以法国数学家西蒙丹尼泊松(Simon Denis Poisson)的名字命名,适用于计算“事件发生次数”的概率,比如交通事故发生次数、产品缺陷数…...

【数学建模竞赛】各类题型及解题方案

评价类赛题建模流程及总结 建模步骤 建立评价指标->评价体系->同向化处理&#xff08;都越多越好或越少越少&#xff09;->指标无量纲处理 ->权重-> 主客观->合成 主客观评价问题的区别 主客观概念主要是在指标定权时来划分的。主观评价与客观评价的区别…...

【12期】谈一谈redis两种持久化机制的区别?

Redis两类持续性的方法 RDB方案可以在规定时间间隔内创建数据集的时间点快照。 AOF方案记录了服务器执行的所有写操作命令&#xff0c;并在服务器启动时通过重新执行这些命令来还原数据集。AOF文件完全遵循Redis协议格式保存&#xff0c;新命令会被追加到文件末尾。此外&#…...

Lambda 编程(Kotlin)一

学习记录&#xff0c;以下为个人理解 知识点&#xff1a; Lambda的定义&#xff1a;允许你把代码块当作参数传递给函数Lambda的语法约定&#xff1a;如果lambda 表达式是函数调用的最后一个实参&#xff0c;它可以放到括号的外边当lambda表达式时函数唯一的实参时&#xff0c…...

网络字节序——TCP接口及其实现简单TCP服务器

网络字节序——TCP接口及其实现简单TCP服务器 文章目录 网络字节序——TCP接口及其实现简单TCP服务器简单TCP服务器的实现1. 单进程版&#xff1a;客户端串行版2. 多进程版&#xff1a;客户端并行版netstat查看网络信息3.多线程版&#xff1a;并行执行log.hpp 守护进程fg、bg s…...

RxJS如何根据事件创建Observable对象?

RxJS提供了一些用来创建Observable对象的函数&#xff0c;我们可以根据事件、定时器、Promise&#xff0c;AJAX等来创建Observable对象。 下面是根据事件创建Observable对象的几个例子。 this.outsideClick$ fromEvent(document, click).subscribe((event: MouseEvent) > …...

网站常见安全漏洞 | 青训营

Powered by:NEFU AB-IN 文章目录 网站常见安全漏洞 | 青训营 网站基本组成及漏洞定义服务端漏洞SQL注入命令执行越权漏洞SSRF文件上传漏洞 客户端漏洞开放重定向XSSCSRF点击劫持CORS跨域配置错误WebSocket 网站常见安全漏洞 | 青训营 网站常见安全漏洞-网站基本组成及漏洞定义…...

vue2使用 vis-network 和 vue-vis-network 插件封装一个公用的关联关系图

效果图&#xff1a; vis组件库&#xff1a;vis.js vis-network中文文档&#xff1a;vis-network 安装组件库&#xff1a; npm install vis-network vue-vis-network 或 yarn add vis-network vue-vis-network 新建RelationGraph.vue文件&#xff1a; <template><…...

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。

LeetCode第73题矩阵置零 1.思路&#xff1a; 想到一个开辟一点空间来解决方法&#xff0c;使用哈希集。就是使用一个哈希集&#xff08;row和col&#xff09;来储存数组中的元素为0的下标。然后再遍历&#xff0c;整个二维数组&#xff0c;在哈希集中存在对应的下标&#xff0c…...

java-初识Servlet,Tomcat,JDBC

文章目录 前言一、ServletServlet 生命周期Servlet 实例Servlet 过滤器 二、TomcatJDBCJDBC连接数据库实例 总结 前言 java入门须知的重要概念/名词/技术 等 一、Servlet Servlet是Java Web开发中的一个核心组件&#xff0c;它是基于Java语言编写的服务器端程序&#xff0c;…...

SpringBoot+mybatis+pgsql多个数据源配置

一、配置文件 jdk环境&#xff1a;1.8 配置了双数据源springbootdruidpgsql&#xff0c;application.properties配置修改如下&#xff1a; #当前入库主数据库 spring.primary.datasource.typecom.alibaba.druid.pool.DruidDataSource spring.primary.datasource.driver-class…...

视频汇聚/视频监控管理平台EasyCVR接入海康SDK协议后无法播放该如何解决?

开源EasyDarwin视频监控/安防监控/视频汇聚EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#…...

MQ消息队列(主要介绍RabbitMQ)

消息队列概念&#xff1a;是在消息的传输过程中保存消息的容器。 作用&#xff1a;异步处理、应用解耦、流量控制..... RabbitMQ&#xff1a; SpringBoot继承RabbitMQ步骤&#xff1a; 1.加入依赖 <dependency><groupId>org.springframework.boot</groupId&g…...

2023年7月天猫糕点市场数据分析(天猫数据怎么看)

烘焙食品行业是近几年食品领域比较火热的赛道之一&#xff0c;随着居民饮食结构的变化&#xff0c;人均消费水平的上升&#xff0c;蛋糕、面包等烘焙糕点越发成为消费者饮食的重要组成部分。同时&#xff0c;在烘焙糕点市场中&#xff0c;老品牌不断推新迭变&#xff0c;新品牌…...

开源双语对话语言模型 ChatGLM-6B 本地私有化部署

本文首发于&#xff1a;https://www.licorne.ink/2023/08/llm-chatglm-6b-local-deploy/ ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级…...

Zabbix 5.0 媒体介质 邮箱配置例子

QQ企业邮箱 参考&#xff1a;zabbix 腾讯企业邮箱配置图_harveymomo的博客-CSDN博客...

基于Red Hat Enterprise Linux 7操作系统的PostgresSql15的备份恢复(实践笔记)

零、前言 本文是基于阿里云ECS服务器进行的实践操作&#xff0c;操作系统版本&#xff1a;Red Hat Enterprise Linux 7 PG数据库版本&#xff1a;PostgresSql 15 PG安装方式&#xff1a;yum 由于本人新接触pg数据&#xff0c;本次也是出于好奇&#xff0c;就对pg数据库的pg_du…...

AMEYA360:类比半导体推出小尺寸低功耗仪表放大器INA103和INA104

致力于提供高品质芯片的国内优秀模拟及数模混合芯片设计商上海类比半导体技术有限公司(下称“类比半导体”或“类比”)宣布推出小尺寸、低功耗、高性能、零漂移仪表放大器INA103和INA104。该系列产品仅需要一个外部电阻即可设置1到10000的增益&#xff0c;静态电流仅为1.3mA并具…...

【Ubuntu20.04】安装gcc11 g++11, Ubuntu18.04

#查看当前使用的gcc版本命令: gcc -v #更新软件源指令&#xff1a; sudo apt-get update #更新软件指令&#xff1a; sudo app-get upgrade# 添加相应的源 sudo add-apt-repository ppa:ubuntu-toolchain-r/test #更新软件源指令&#xff1a; sudo apt-get update# 卸载已有gcc…...

vim系列之常用命令

一.欢迎来到我的酒馆 在本章节介绍vim编辑器常用命令。 目录 一.欢迎来到我的酒馆二.vim常用命令 二.vim常用命令 2.1vim编辑器常用命令&#xff1a; i: 在光标位置处插入字符。o: 在下一行开始位置插入一行。yy: 复制光标所在的行p: 在光标位置粘贴剪切板内容。...

Scikit-Learn中的特征选择和特征提取详解

概要 机器学习在现代技术中扮演着越来越重要的角色。不论是在商业界还是科学领域&#xff0c;机器学习都被广泛地应用。在机器学习的过程中&#xff0c;我们需要从原始数据中提取出有用的特征&#xff0c;以便训练出好的模型。但是&#xff0c;如何选择最佳的特征是一个关键问…...

Python之动态规划

序言 最近在学习python语言&#xff0c;语言有通用性&#xff0c;此文记录复习动态规划并练习python语言。 动态规划&#xff08;Dynamic Programming&#xff09; 动态规划是运筹学的一个分支&#xff0c;是求解决策过程最优化的过程。20世纪50年代初&#xff0c;美国数学家…...

[ES]二基础 |

一、索引库操作 1、mapping属性 mapping是对索引库中文档的约束&#xff0c;常见的mapping属性包括&#xff1a; 1)type&#xff1a;字段数据类型&#xff0c;常见的简单类型有&#xff1a; ①字符串&#xff1a;text(可分词的文本)、keyword&#xff08;精确值&#xff0c…...

vscode vue3自定义自动补全

敲代码多了&#xff0c;发现重发动作很多&#xff0c;于是还是定义自动补全代码吧——懒是第一生产力&#xff01; 1&#xff0c;Ctrl Shift P打开快捷命令行&#xff1a;找到下面这个 2&#xff0c;然后找到ts&#xff1a; 里面给了demo照着写就行 // "Print to conso…...

Spring Cloud + Spring Boot 项目搭建结构层次示例讲解

Spring Cloud Spring Boot 项目搭建结构层次示例讲解 Spring Cloud 项目搭建结构层次示例Spring Cloud示例&#xff1a; Spring Boot 项目搭建结构层次讲解Spring Boot 项目通常按照一种常见的架构模式组织&#xff0c;可以分为以下几个主要层次&#xff1a;当构建一个 Spring…...

使用cgroup工具对服务器某些/全部用户进行计算资源限制

使用cgroup工具对服务器某些/全部用户进行计算资源限制 主要介绍&#xff0c;如何对指定/所有用户进行资源限定&#xff08;这里主要介绍cpu和内存占用限制&#xff09;&#xff0c;防止某些用户大量占用服务器计算资源&#xff0c;影响和挤占他人正常使用服务器。 安装cgrou…...

C#获取DataTable的前N行数据然后按指定字段排序

获取DataTable的前N行数据然后按指定字段排序 可以使用以下三种代码&#xff1a; 第一种&#xff1a;使用Linq DataTable dtLast dataTable.AsEnumerable().Take(count).OrderBy(dataRow > Convert.ToInt32(dataRow["Sequence"])).CopyToDataTable(); 第二种…...

Swift 中的动态成员查找

文章目录 前言基础介绍基础示例1. 定义一个动态成员访问类&#xff1a;2. 访问嵌套动态成员&#xff1a; 使用 KeyPath 的编译时安全性KeyPath 用法示例KeyPath 进阶使用示例1. 动态访问属性&#xff1a;2. 结合可选属性和 KeyPath&#xff1a;3. 动态 KeyPath 和字典&#xff…...

leetcode做题笔记102. 二叉树的层序遍历

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 思路一&#xff1a;递归 int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){int** ans(int**)mal…...

python编写四画面同时播放swap视频

当代技术让我们能够创建各种有趣和实用的应用程序。在本篇博客中&#xff0c;我们将探索一个基于wxPython和OpenCV的四路视频播放器应用程序。这个应用程序可以同时播放四个视频文件&#xff0c;并将它们显示在一个GUI界面中。 C:\pythoncode\new\smetimeplaymp4.py 准备工作…...

用XSIBackup为VMware ESXi打造完美备份方案

文章目录 VMware ESXi 备份方案引言XSIBackup安装步骤1. XSIBackup软件安装2. SSH连接3. 定位到xsibackup目录4. 修改文件权限5. 安装cron查看crontab列表6. 配置备份任务结论VMware ESXi 备份方案 引言 数据就像是我们的生命线,一旦丢失,可能会带来无法挽回的损失。对于那…...

React 项目中引入msal验证以及部分报错处理

功能实现 如何在React 项目中引入msal身份验证&#xff0c; 微软在官网有提供文档支持&#xff0c;文档包含示例和具体使用的教程&#xff0c;地址如下&#xff1a; https://learn.microsoft.com/zh-cn/azure/active-directory/develop/tutorial-v2-nodejs-webapp-msal 照着文…...

Unity3D 2021 使用 SharpZipLib 遇到的安卓打包 I18N 相关问题

在 Unity3D 中&#xff0c;使用 ICSharpCode.SharpZipLib.dll 来做压缩和解压缩&#xff0c;但打包安卓后遇到问题&#xff0c;原因是字符编码程序集被裁减掉了导致。 根据网上搜索&#xff0c;将 UnityEditor 对应目录下的 I18N开头的&#xff0c;比如 I18N.CJK.dll 等系列文…...

软件工程(十五) 行为型设计模式(一)

1、责任链模式 简要说明 通过多个对象处理的请求,减少请求的发送者与接收者之间的耦合。将接受对象链接起来,在链中传递请求,直到有一个对象处理这个请求。 速记关键字 传递职责 类图如下 由类图可以比较容易的看出来,其实就是自己关联自己,形成了一个链,并且自己有…...