[C++]:C++11(一)

1. 统一列表初始化

1.1 C++11 之前的初始化方式

在 C++11 标准中,引入了一个非常实用且强大的特性——统一列表初始化(Uniform Initialization),它为我们在初始化各种类型的对象时提供了一种统一且方便的语法形式,极大地改善了代码的可读性以及初始化操作的灵活性。

在 C++11 之前,初始化不同类型的对象往往有着不同的语法规则,例如:

  • 对于普通内置类型,我们可以像这样初始化:
int a = 5;  // 传统的赋值初始化方式
  • 对于数组,可以使用如下方式:
int arr[3] = {1, 2, 3};
  • 而对于类对象,如果有合适的构造函数,可能会通过构造函数来初始化,像:
class MyClass {
public:
    MyClass(int x, int y) : m_x(x), m_y(y) {}
private:
    int m_x;
    int m_y;
};

MyClass obj(10, 20);  // 通过构造函数初始化对象

这种多样化的初始化语法在复杂的代码环境中容易造成混淆,并且当涉及到更复杂的类型(比如 STL 容器等)时,初始化的方式可能不够直观。C++11 的统一列表初始化旨在解决这些问题,提供一种通用的、能适用于多种类型的初始化语法。

统一列表初始化使用花括号 {} 来进行初始化操作,以下是一些常见的示例展示其语法应用:

1.2 内置类型初始化

int num{10};  // 使用统一列表初始化语法初始化整型变量
double d = {3.14};  // 初始化双精度浮点型变量

这里不再局限于传统的 = 赋值初始化方式,通过花括号可以更直观地表示这是一个初始化操作。使用初始化列表时,可添加等号(=),也可不添加。

1.3 数组初始化

int arr[]{1, 2, 3};  // 省略数组大小,编译器会根据初始化列表中的元素个数自动推断数组大小
int anotherArr[5]{1, 2};  // 部分初始化,未指定的元素会被初始化为 0(对于基本数据类型而言)
int* pa = new int[4]{ 0 };//new表达式也可同时初始化

与之前的数组初始化语法相比,更加简洁明了,尤其是省略数组大小的情况,让代码更具灵活性。

1.4 类对象初始化

1.4.1 默认构造函数情况

如果类有默认构造函数,我们可以这样初始化对象:

class SimpleClass {
public:
    SimpleClass() {}
};

SimpleClass sc{};  // 使用统一列表初始化调用默认构造函数
1.4.2 带参数构造函数情况

对于带有参数的构造函数的类,可以直接传递参数列表在花括号内进行初始化:

class Point {
public:
    Point(int x, int y) : m_x(x), m_y(y) {}
private:
    int m_x;
    int m_y;
};

Point p{3, 5};  // 通过统一列表初始化调用带两个参数的构造函数

1.5 initializer_list 容器

initializer_list 是 C++11 一个标准库中的类模板。它的主要作用是用于表示一个特定类型的元素列表,旨在方便地处理那些能够以列表形式进行初始化的情况,比如在类的构造函数中接收一组初始化值,或者用于函数参数传递一组同类型的数据等。

1.5.1 初始化

要使用 initializer_list,首先需要包含对应的头文件 <initializer_list>,然后就可以像声明其他模板类型一样来声明它。例如,如果我们想创建一个用于存放整型数据的 initializer_list,可以这样写:

#include <initializer_list>
#include <iostream>

int main() {
    std::initializer_list<int> my_list = {1, 2, 3};
    return 0;
}

在上述代码中,std::initializer_list<int> 声明了一个能够容纳整型元素的 initializer_list 类型的对象 my_list,并通过花括号 {} 初始化它,使其包含了 123 这三个整型元素。

1.5.2 访问元素

initializer_list 提供了类似于容器的访问方式,不过它相对来说比较简单,主要有两个常用的成员函数:begin()end()。这两个函数返回的是指向列表中第一个元素和最后一个元素之后位置的迭代器(遵循 STL 容器迭代器的通用规则),我们可以利用这两个迭代器来遍历整个列表中的元素。示例如下:

#include <initializer_list>
#include <iostream>

int main() {
    std::initializer_list<int> my_list = {4, 5, 6};
    for (auto it = my_list.begin(); it!= my_list.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

在这个示例中,通过迭代器遍历 initializer_list 中的元素,并将每个元素输出到控制台,最终会打印出 4 5 6

此外,由于 initializer_list 支持基于范围的 for 循环,所以我们也可以更简洁地遍历它,如下所示:

#include <initializer_list>
#include <iostream>

int main() {
    std::initializer_list<int> my_list = {7, 8, 9};
    for (int element : my_list) {
        std::cout << element << " ";
    }
    return 0;
}

同样,这段代码也能正确地将 789 依次打印出来,基于范围的 for 循环在内部其实也是利用了 begin()end() 这两个迭代器来实现元素的遍历。

需要注意的是,initializer_list 所表示的元素列表是不可变的,也就是说一旦创建了 initializer_list 对象,就不能修改其内部的元素了。例如,下面这样尝试修改元素的代码是无法通过编译的:

#include <initializer_list>
#include <iostream>

int main() {
    std::initializer_list<int> my_list = {10, 11, 12};
    // 以下代码会编译出错,因为不能修改 initializer_list 中的元素
    *(my_list.begin()) = 13;
    return 0;
}

这种不可变的特性符合它通常用于初始化操作的设计初衷,确保传递进来的初始化数据在初始化过程中不会被意外更改。

1.5.3 应用

当一个类存在多个构造函数时,包含接收 initializer_list 的构造函数会参与到构造函数的重载决议中。通常情况下,如果调用构造函数时传递的参数形式符合 initializer_list 的初始化列表形式,那么编译器会优先调用对应的接收 initializer_list 的构造函数。例如:

class MyClass {
public:
    MyClass(int value) {
        std::cout << "Constructor with single int parameter called." << std::endl;
    }
    MyClass(std::initializer_list<int> list) {
        std::cout << "Constructor with initializer_list parameter called." << std::endl;
    }
};

int main() {
    MyClass obj1(5);  // 调用单个整型参数的构造函数
    MyClass obj2({5});  // 调用接收 initializer_list 的构造函数
    MyClass obj3{5};  // 同样调用接收 initializer_list 的构造函数
    return 0;
}

在这个例子中,obj1 的初始化调用了普通的带单个整型参数的构造函数,而 obj2obj3 的初始化由于传递参数的形式是花括号包裹的单个元素,符合 initializer_list 的语法特征,所以编译器会调用接收 initializer_list 的构造函数。

所以说 initializer_list为一些不定参数的类,提供了一种更加方便的初始化方式。

class ComplexClass {
public:
    ComplexClass(std::initializer_list<int> list) {
        for (auto element : list) {
            // 进行一些基于初始化列表元素的操作
        }
    }
};

ComplexClass cc{1, 2, 3};  // 调用接受初始化列表的构造函数

特别是对于标准模板库(STL)中的容器,如 vectorlistmap 等,这一点得到了很好的应用。

vector<int> v = { 1,2,3,4 };
list<int> lt = { 1,2 };
// 这里{"sort", "排序"}会先初始化构造一个pair对象
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
// 使用大括号对容器赋值
v = {10, 20, 30};

之所以能够这样使用的原因就是 STL 容器在实现时提供了对应的 initializer_list构造对应对象的构造函数与赋值重载。比如说,以下是 list的构造函数:

2. 变量类型推导

2.1 auto

2.1.1 auto 的使用

在传统的 C++ 编程中,声明变量时需要明确指定变量的类型,例如:

int num = 10;
double pi = 3.14;
std::string str = "Hello, World!";

然而,随着 C++ 语言的发展以及模板编程、STL(标准模板库)等复杂特性的广泛应用,类型的书写有时候会变得非常冗长和繁琐,尤其是涉及到一些复杂的模板类型或者函数返回值类型难以直接明确表述时。auto 关键字就是为了解决这个问题而诞生的,它能够让编译器根据变量的初始值自动推导出变量的类型。

简单来说,使用 auto 关键字,我们可以在声明变量时省略具体的类型声明部分,让编译器帮我们去确定这个变量实际应该是什么类型,代码的书写也就变得更加简洁。例如:

auto num = 10;  // 编译器自动推导出 num 为 int 类型
auto pi = 3.14;  // 编译器自动推导出 pi 为 double 类型
auto str = std::string("Hello, World!");  // 编译器自动推导出 str 为 std::string 类型
2.1.2 注意事项

如果初始化表达式带有顶层 const(即修饰变量本身,表示变量的值不能被修改),使用 auto 推导时,顶层 const 会被忽略,变量本身不会成为 const 类型。例如:

const int num = 10;
auto var = num;  // var 的类型为 int,顶层 const 被忽略,var 可以被重新赋值

但是,如果想要保留顶层 const 属性,可以使用 const auto 的形式来声明变量,如下所示:

const int num = 10;
const auto var = num;  // var 的类型为 const int,不能被重新赋值

对于底层 const(即修饰指针或引用所指向的对象,表示不能通过该指针或引用修改所指向的对象),auto 关键字会正确地推导并保留底层 const 属性。例如:

const int num = 10;
const int* ptr = &num;
auto new_ptr = ptr;  // new_ptr 的类型为 const int*,保留了底层 const,不能通过 new_ptr 修改所指向的对象

2.2 decltype

decltype的主要作用是用于查询表达式的类型,编译器会根据给定表达式的实际类型来推导出对应的类型,然后可以用这个推导出的类型去定义变量、作为函数返回值类型等。

简单来说,就是让编译器帮你自动确定某个表达式的类型是什么,而不需要你显式地去指定类型。

2.2.1 语法形式

decltype(表达式)就是其基本语法结构,例如:

int num = 10;
decltype(num) anotherNum;  // anotherNum被推导为int类型,因为num是int类型

这样,当你已经有了一个确定类型的变量,又想定义同类型的其他变量时,decltype就很方便,不需要重复写具体的类型(尤其是对于复杂类型,比如自定义结构体指针类型等情况,使用decltype能避免手动书写复杂类型名时出错)。

2.2.2 函数返回值类型的推导

在C++11 之前,函数返回值类型需要在函数声明时就明确写出来,但是有些复杂情况很难提前确定具体类型,这时decltype就可以帮忙了。例如:

template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {  // 根据a+b表达式的类型来确定函数返回值类型
    return a + b;
}

上述代码定义了一个函数模板add,它可以接受不同类型的参数(T1T2类型),然后通过decltype(a + b)来让编译器自动推导a + b运算结果的类型,并将这个类型作为函数add的返回值类型。这样函数就能灵活地适应各种支持+运算的不同类型参数组合了,比如intdouble相加、两个自定义类对象(如果重载了+运算符)相加等情况。

2.2.3 配合typedef或using
int arr[5];
using ArrayType = decltype(arr);  // 使用decltype推导arr的类型(在这里是int[5],即包含5个元素的int数组类型),并定义别名ArrayType
ArrayType anotherArr;  // 相当于定义了int[5]类型的anotherArr数组

这种方式可以方便地给一些复杂的、通过表达式才能确定的类型创建一个更简洁易懂的别名,便于后续代码中使用该类型进行变量定义等操作。

2.2.4 注意实现

decltype在推导类型时,括号的存在与否可能会导致不同的结果。例如:

int num = 10;
decltype((num)) refToNum = num;  // 这里推导的是int&类型,是num的引用,因为(num)是一个左值表达式
decltype(num) anotherNum = num;  // 这里推导的是int类型,anotherNum是一个新的int变量

在使用时要特别留意,如果想推导得到引用类型,通常可以使用带括号的表达式形式(前提是该表达式本身对应的是一个左值)。

2.2.5 与auto的区别

虽然autodecltype都和类型推导相关,但它们有明显不同:

  • auto是根据变量初始化表达式来推断变量的类型,并且它推断出来的几乎都是值类型(非引用类型,除非明确使用&&&修饰),比如auto x = 5;x就是int类型(值类型)。
  • decltype是根据给定的表达式本身的类型来推导,不管这个表达式是左值、右值等情况,而且它能准确推导出引用类型等,就像前面例子中展示的那样,decltype((num))推导出的就是引用类型。

2.3 nullptr

在C++早期版本中,通常使用NULL来表示空指针。然而,NULL实际上是一个宏定义,在C语言中它一般被定义为(void *)0,但在C++中,为了保持类型安全(因为 C++ 中不能直接将void *类型隐式转换为其他指针类型),它被定义为整数类型的0

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else  /* __cplusplus */
#define NULL    ((void *)0)
#endif  /* __cplusplus */
#endif  /* NULL */

这就可能导致一些混淆和潜在的类型不匹配问题,特别是在函数重载等场景下。例如:

void func(int i) {
    std::cout << "Called func(int)" << std::endl;
}

void func(void *p) {
    std::cout << "Called func(void *)" << std::endl;
}

int main() {
    func(NULL);  // 在C++中,会调用func(int),而不是期望中的func(void *),因为NULL被当作整数0处理了
    return 0;
}

为了解决这类问题,C++11引入了nullptr关键字来明确地表示空指针,它具有更好的类型安全性

  • 类型特性nullptr的类型是std::nullptr_t,这是一种特殊的类型。所有的指针类型都可以隐式转换为std::nullptr_t类型,反过来,std::nullptr_t类型也可以隐式转换为所有的指针类型,这使得它能很自然地在各种涉及指针的场景中表示空指针的情况。例如:
int *ptr1 = nullptr;  // 正确,将nullptr赋值给int指针类型
double *ptr2 = nullptr;  // 同样正确,用于double指针类型
  • 语法使用:在代码中,当你需要将一个指针初始化为空指针状态,或者将一个指针赋值为空指针时,就可以直接使用nullptr。比如:
class MyClass {
    // 类的定义相关内容
};

MyClass *objPtr = nullptr;  // 初始化一个指向MyClass对象的空指针
if (objPtr == nullptr) {
    // 执行相关逻辑,判断指针是否为空
}

3. 范围 for

C++11 中的范围 for 循环(也称作基于范围的 for 循环,Range-based for loop)是一种语法糖,它提供了一种简洁且方便的方式来遍历容器(如数组、vectorlist 等)或其他可迭代对象中的元素。以下是关于它的详细介绍:

范围 for 循环的基本语法格式如下:

for ( decltype(容器)::value_type& 元素变量名 : 容器对象 ) {
    // 循环体,在这里可以对元素变量名所代表的元素进行操作
}

不过在实际使用中,更常见、更简洁的写法是(编译器会自动进行合适的类型推导等处理):

for ( auto& 元素变量名 : 容器对象 ) {
    // 循环体,对元素进行操作
}

例如,下面分别是使用传统 for 循环和范围 for 循环遍历 vector 容器的示例对比:

传统 for 循环遍历 vector

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (size_t i = 0; i < vec.size(); ++i) {
        std::cout << vec[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

使用范围 for 循环遍历 vector

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (auto& element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    return 0;
}

可以看到,范围 for 循环的代码更加简洁直观,无需手动去管理索引、判断边界等操作。

当使用范围 for 循环时,编译器实际上会将其展开为类似传统 for 循环的代码形式,它会自动获取容器的开始迭代器和结束迭代器(通过调用容器的 begin()end() 方法,如果容器不支持这两个方法则无法使用范围 for 循环进行遍历),然后按照迭代器的顺序依次访问容器中的每个元素,每次将当前元素绑定到循环中定义的变量上,使得在循环体中可以方便地对元素进行操作。

4. STL 的变化

4.1 新增的容器

首先 C++11中新增了四个容器,分别是 arrayforward_listunordered_mapunordered_set。其中 unordered_mapunordered_set在前面我们已经介绍过了,接下来我们来简要介绍一下 arrayforword_list

4.1.1 array 容器

array是C++11引入的一个固定大小的数组容器,它位于<array>头文件中。它封装了C++中内置的普通数组,提供了更符合现代C++编程风格的接口以及一些额外的便利性和安全性保障,在行为表现上更像是一个“智能数组”。

特点及优势

  • 固定大小:与普通的C风格数组一样,在定义时就确定了其大小,后续不能动态改变。例如:std::array<int, 5> myArray; 就定义了一个能容纳5个int类型元素的std::array,这个大小在编译时就固定下来了。
  • 安全性提升:它避免了普通数组常见的一些越界访问等问题,因为它重载了[]运算符等操作,并且会在编译阶段对一些非法访问进行检查。例如,当你试图访问超出其大小范围的元素时,编译器会报错,而不像普通数组那样可能在运行时产生难以察觉的错误(比如访问了未初始化的内存区域等情况)。

例如:

#include <iostream>
#include <array>

int main() {
    std::array<int, 4> arr = {1, 2, 3, 4};
    for (size_t i = 0; i < arr.size(); ++i) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}
4.1.2 forward_list

forward_list是C++11引入的一个单向链表容器,定义在<forward_list>头文件中。它只支持单向的遍历,即只能从链表头开始依次向后访问节点,每个节点包含数据以及指向下一个节点的指针,与双向链表(如std::list)相比,它的空间开销更小,因为不需要额外存储指向前一个节点的指针。

特点及优势

  • 空间效率:由于没有前向指针,对于内存空间比较敏感且只需要单向顺序访问的应用场景来说,它能节省一定的内存空间,在存储大量节点时这种空间优势可能会比较明显。
  • 插入和删除操作高效(在特定位置):在链表头部进行元素的插入和删除操作非常高效,时间复杂度为常数级别O(1),因为只需要简单地调整指针指向即可。

例如:

#include <iostream>
#include <forward_list>

int main() {
    std::forward_list<int> flist;
    flist.push_front(1);  // 在链表头部插入元素1,效率很高
    flist.push_front(2);  // 再插入元素2
    for (auto& element : flist) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    return 0;
}

4.2 字符串转换函数

C++11也提供了各种内置类型与 string 之 间相互转换的函数,比如 to_stringstoistolstod 等函数。

除此之外C++11 也为每个容器都增加了一些新方法,比如:

  • 提供了一个以 initializer_list 作为参数的构造函数,用于支持列表初始化。
  • 提供了 cbegincend 方法,用于返回const迭代器。
  • 提供了 emplace 系列方法,并在容器原有插入方法的基础上重载了一个右值引用版本的插入函数,用于提高向容器中插入元素的效率。

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

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

相关文章

基于的图的异常检测算法OddBall

OddBall异常检测算法出自2010年的论文《OddBall: Spotting Anomalies in Weighted Graphs》&#xff0c;它是一个在加权图(weighted graph)上检测异常点的算法&#xff0c;基本思路为计算每一个点的一度邻域特征&#xff0c;然后在整个图上用这些特征拟合出一个函数&#xff0c…

基于AOA算术优化的KNN数据聚类算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于AOA算术优化的KNN数据聚类算法matlab仿真。通过AOA优化算法&#xff0c;搜索最优的几个特征数据&#xff0c;进行KNN聚类&#xff0c;同时对比不同个数特征下…

【模块一】kubernetes容器编排进阶实战之CoreDNS的介绍与使用

CoreDNS进阶 CoreDNS进阶-简介 DNS组件历史版本有skydns、kube-dns和coredns三个&#xff0c;k8s 1.3版本之前使用skydns&#xff0c;之后的版本到1.17及之间的版本使用kube-dns&#xff0c; 1.18开始目前主要使用coredns&#xff0c;DNS组件用于解析k8s集群中service name所对…

栈Stack和队列Queue

目录 一、栈 &#xff08;1&#xff09;用数组实现 &#xff08;2&#xff09;用单链表实现 &#xff08;3&#xff09;用标注尾结点的单链表实现 &#xff08;4&#xff09;用双向链表实现 2、栈的实际应用 &#xff08;1&#xff09;改变元素的序列 &#xff08;2&am…

ES6标准-Promise对象

目录 Promise对象的含义 Promise对象的特点 Promise对象的缺点 Promise对象的基本用法 Promise对象的简单例子 Promise新建后就会立即执行 Promise对象回调函数的参数 Promise参数不会中断运行 Promise对象的then方法 Promise对象的catch()方法 Promise状态为resolv…

【隐私计算】隐私计算的应用场景探索(大模型隐私计算、隐私数据存储计算、Web3、隐私物联网等)

1. 背景分析 隐私计算作为一种实现“原始数据不出域&#xff0c;可用不可见”的数据流通价值的关键技术&#xff0c;经历了2020-2023年的高光时刻&#xff0c;却在2024年骤然走向低谷。从各种渠道了解到一些业内曾经风光无两的隐私计算公司都有不同程度的裁员。几乎一夜之间&am…

【大数据学习 | flume】flume的概述与组件的介绍

1. flume概述 Flume是cloudera(CDH版本的hadoop) 开发的一个分布式、可靠、高可用的海量日志收集系统。它将各个服务器中的数据收集起来并送到指定的地方去&#xff0c;比如说送到HDFS、Hbase&#xff0c;简单来说flume就是收集日志的。 Flume两个版本区别&#xff1a; ​ 1&…

【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法

【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法 目录 文章目录 【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法目录摘要&#xff1a;研究背景&#xff1a;问题与挑战&#xff1a;如何解…

数据库审计工具--Yearning 3.1.9普民的使用指南

1 页面登录 登录地址:18000 &#xff08;不要勾选LDAP&#xff09; 2 修改用户密码 3 DML/DDL工单申请及审批 工单申请 根据需要选择【DML/DDL/查询】中的一种进行工单申请 填写工单信息提交SQL检测报错修改sql语句重新进行SQL检测&#xff0c;如检测失败可以进行SQL美化后…

Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV买卖股票的最佳时机III

Day44 | 动态规划 &#xff1a;状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III&&309.买卖股票的最佳时机含冷冻期 动态规划应该如何学习&#xff1f;-CSDN博客 本次题解参考自灵神的做法&#xff0c;大家也多多支持灵神的题解 买卖股票的最佳时机【…

Windows配置域名映射IP

一、找到 hosts 文件 打开 C:\Windows\System32\drivers\etc 二、添加hosts文件修改、写入权限 右击hosts文件&#xff0c;点击属性 -> 安全 -> Users -> 编辑 -> Users -> 添加修改、写入权限 -> 确定 -> 确定 进入常规&#xff0c;将只读属性关闭 三、…

sapiens推理的安装与使用

文章目录 1、安装1.1 克隆代码库1.2 设置 Sapiens-Lite 的代码路径1.3 创建 Conda 环境并安装必要的依赖1.4 下载模型检查点 2、推理 sapiens&#xff0c;是meta发布的以人为中心的视觉大模型&#xff0c;"sapiens"这个词来源于拉丁语&#xff0c;意为“智慧的”或“…

黑马智数Day10

项目背景说明 后台管理部分使用的技术栈是Vue2&#xff0c;前台可视化部分使用的技术栈是Vue3 前台可视化项目不是独立存在&#xff0c;而是和后台管理项目共享同一个登录页面 微前端的好处 微前端是一种前端架构模式&#xff0c;它将大型单体应用程序分解为小的、松散耦合的…

A3超级计算机虚拟机,为大型语言模型LLM和AIGC提供强大算力支持

热门大语言模型项目地址&#xff1a;www.suanjiayun.com/mirrorDetails?id66ac7d478099315577961758 近几个月来&#xff0c;我们目睹了大型语言模型&#xff08;LLMs&#xff09;和生成式人工智能强势闯入我们的视野&#xff0c;显然&#xff0c;这些模型在训练和运行时需要…

乐维网管平台(七):网络稳定与高效的“安全锦囊”

试想一下&#xff0c;你给电脑升级了一个软件&#xff0c;升级完成后发现有BUG&#xff0c;经常无故卡死&#xff0c;这时候想回退或重新安装旧版本…相对地&#xff0c;一家企业的网络管理员&#xff0c;在对公司的核心交换机进行复杂的配置调整时&#xff0c;一个小小的疏忽&…

基于Python的图片信息推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

没钱买KEGG怎么办?REACTOME开源通路更强大

之前搜集免费生物AI插图时简单提到了通路数据库Reactome&#xff08;https://reactome.org/&#xff09;&#xff0c; 那些精美的生物插图只能算是该数据库附赠的小礼品&#xff0c;他的主要功能还是作为一个开源的通路数据库&#xff0c;为相关领域的研究者提供直观的可视化生…

spi 回环

///tx 极性0 &#xff08;sclk信号线空闲时为低电平&#xff09; /// 相位0 (在sclk信号线第一个跳变沿进行采样) timescale 1ns / 1ps//两个从机 8d01 8d02 module top(input clk ,input rst_n,input [7:0] addr ,input …

Lc70--319.两个数组的交集(二分查找)---Java版

1.题目描述 2.思路 用集合求交集&#xff0c;因为集合里面的元素要满足不重复、无序、唯一。使得集合在去重、查找和集合操作&#xff08;如交集、并集、差集等&#xff09;中非常高效和方便。 3.代码实现 class Solution {public int[] intersection(int[] nums1, int[] nu…

项目2:简易随机数生成器 --- 《跟着小王学Python·新手》

项目2&#xff1a;简易随机数生成器 — 《跟着小王学Python新手》 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握P…