c++ primer plus笔记 第十八章 探讨c++新标准

复习前面的内容:
1.auto,可以自动识别auto本身在这种语境下是什么类型

2.decltype,让一个变量的类型和另外一个变量的类型相同

decltype(x) y;//让y的类型和x的类型相同

如何理解?

decltype是一个关键词,其作用是检查括号内的表达式,并返回该表达式的类型,因此相当于用返回表达式的类型定义了y。

使用decltype的时候,需要注意的是:
 

int i;
decltype(i) j;//此时j是int类型
decltype((i)) j;//此时j的int&类型
//原因是在i外面再加一圈括号则会被看作为一个表达式,返回的类型将是内括号类型的引用

当定义一个模板函数的时候,有时候没办法确定返回的类型,比如说传入的一个是int类型,一个是double类型的时候返回的是double类型,如果传入的是两个int类型的时候,返回是int类型,为了解决这种情况,则可以使用decltype,

template<class T, class U>
auto sum(T &n, U m)->decltype(n+m)
{
    return n+m;
}

函数执行的顺序是,先传入参数,然后执行decltype关键词,auto根据decltype返回的类型来决定自己的类型。

3.回顾模板类中的隐式实例化,显示实例化,全部具体化,部分具体化

template<class T>;
template<typename T>;
//这两个模板头是一个意思,只是习惯问题,有些人喜欢用class,有些人喜欢用typename

1)隐式实例化,就像我们平时实例化一个模板类,用模板类创造一个对象就是在使用隐式实例化

template<class T>
class A
{
};
int main(void)
{

    A<int > a;//隐式实例化
    return 0;
}

2)显示实例化,不需要创造对象即可定义模板

template<class T>
class A
{
};
template class A<int >;//显示实例化, 不需要定义对象,但却实例化了模板类
int main(void)
{

    return 0;
}

3)全部具体化

具体化就是将类型参数限制住,使得模板类更加具体,当传入的类型参数为限制的类型的时候,使用的即为这个更具体的模板类的声明。

template <typename T, typename U>
class MyClass {
    //...
};
template <>//<>括号内填入不进行具体化的类型参数,全具体化没有不进行具体化的参数
class MyClass<int, double> {//对类型参数具体化
    // 这是一个全具体化版本
    // 当T和U分别为int和double时,会使用这个版本
    //...
};

4)部分具体化

template <typename T, typename U>
class MyClass {
    //...
};

template <typename T>//类型参数T不进行具体化,不进行具体化的类型参数要放进<>中
class MyClass<T, int> {
    // 这是一个部分具体化版本
    // 当U是int类型时,会使用这个版本
};

4.转换函数与单参数的构造函数的隐式转换问题

转换函数是将对象转换成其他类型,如

//定义一个转换函数,将复数对象转换成其实部
class Complex
{
private:
    double real;     // 实部
    double imaginary; // 虚部
 
public:
    // 构造函数
    Complex(double real = 0.0, double imaginary = 0.0) 
        : real(real), imaginary(imaginary)
    { }
 
    // 定义一个转换函数,将Complex对象转换为double
    operator double() const//转换函数不需要返回类型
    {
       return real; // 返回Complex对象的实部
    }
};

我们不希望以下的事情发生:
 

double a;
Complex temp;
a = temp;//这会隐式地将temp对象转换成double类型的数据,这可能不是我们想要发生生的
//则应该在转换函数前面加上explicit来禁止隐式转换,只允许显示转化
a = temp.operator double();//显示调用转换函数

但参数的构造函数可能也会发生类型的情况

比方说:
 

class A
{
    private:
        int num;
    public:
        A(int n = 0) : num(n) {}
}

int main(void)
{
    A temp1(10);
    temp1 = 20;//这将会用20作为参数隐式调用构造函数来创建一个无名对象,然后赋值给temp1;
    return 0;
}

我们不希望这样的事情发生,同样的,可以在这个单参数的构造函数前面加上explicit

5.

基于范围的for

c++11引入了基于范围的for,使得遍历容器或者数组变得更加方便,对于一般的数组:
 

int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i : arr)
    cout << i << endl;
vector<int> arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(auto i : arr)
    cout << i << endl;
//将容器或者数组中的元素放到i中

6.

复习左值,右值,以及左值引用右值引用(第八章第9节)

一般来说,左值就是可以放在等号左边的值,右值就是可以放到等号右边的值,我们有一个技巧可以判断哪个是左值哪个是右值,一般来说,左值可以用&取地址,右值不可能用&取地址。而右值引用可以修改引用所指向的对象,右值引用一般用于移动语句。

什么叫做常引用?
常引用可以指向右值

const int &temp = (a+b);
//这将会在内存中创建一个临时变量来存放a+b,temp将是这个临时变量的别名
//但常引用无法改变该临时变量的值,只能读取

什么是右值引用?

int &&temp = (a+b);//定义一个右值引用

7.

作用域内枚举

当一个类中定义了两个枚举变量,但是这两个枚举变量中有相同的枚举量,我们可以使用类来将枚举量进行封装,然后用作用域来解决这个问题枚举量冲突问题,即在类的作用域中不会出现命名冲突。

class A
{
    public:
        enum class color1{Red,Blue, Green};
        enum class color2{Red, Yellow};//定义两个枚举类,用枚举类来封装枚举量
};
//这样就可以用类名加上作用域解析运算符来指定使用哪个枚举量


A::color1 c1 = A::color1::Red;
A::color2 c2 = A::color2::Red;

if (c1 == A::color1::Red) {
    // do something
}

if (c2 == A::color2::Red) {
    // do something else
}

8.

using=和typedef有什么区别?

c++11中可以使用using加别称 = 模板类名来给模板类起一个别名,而typedef无法做到,毕竟模板类是c++新增的东西。

如:
 

using v = std::vector<int>;
//让v和std::vector<int>等价,即v成为了别名

移动语义和右值引用

移动语义是什么意思?

移动语义是一种理念或方案,它通过避免昂贵的复制操作来提高性能,将右值引用所指向的内存好好利用,使用更改内存所有权的方式来实现复制而不是通过重新开辟内存的方式来复制。而移动构造函数和移动赋值运算符则是实现这种理念的工具或手段。

什么是移动构造函数和移动赋值运算符?

移动构造函数的参数是右值引用,移动构造函数的作用就是将右值引用所指向的对象的内存空间让给移动构造函数所要生成的对象,只是将一个对象的资源转让给另一个对象,相当于把这片内存改了个名字,原来是右值引用所指向的对象拥有的内存,变成了调用移动构造函数的对象的内存,并没有开辟新的内存。

移动赋值运算符也是同理,将右值引用所指向的对象所拥有的内存空间转让给了其他对象,也没有开辟新的内存。

什么时候调用移动构造函数?

当一个临时的对象(或称之为右值)给另一个对象进行初始化的时候,编译器将调用移动构造函数而非复制构造函数,这也是与复制构造函数的区别。

下面是一个使用移动构造函数和移动赋值运算符的例子,帮助理解:

#include <iostream>
#include <vector>

class MyClass {
private:
    int* data;

public:
    MyClass(int size) { // 构造函数
        data = new int[size];
        std::cout << "Constructor called!" << std::endl;
    }

    ~MyClass() { // 析构函数
        delete[] data;
        std::cout << "Destructor called!" << std::endl;
    }

    MyClass(const MyClass& other) = delete; // 禁止复制

    MyClass(MyClass&& other) noexcept : // 移动构造函数,noexcept保证函数不抛出异常,如果抛出异常将会直接终止程序
        data(other.data)
    {
        other.data = nullptr;
        std::cout << "Move constructor called!" << std::endl;
    }

    MyClass& operator=(MyClass&& other) noexcept { // 移动赋值运算符
        if(this != &other) {
            delete[] data; // 删除当前对象的资源
            data = other.data; // 赋值,将资源转让给调用构造函数的对象
            other.data = nullptr; // 置空
            std::cout << "Move assignment operator called!" << std::endl;
        }
        return *this;
    }
};

int main() {
    std::vector<MyClass> vec;

    vec.push_back(MyClass(50)); // push_back会调用移动构造函数

    MyClass a(100); // 正常构造
    MyClass b(200); // 正常构造

    b = std::move(a); // 调用移动赋值运算符

    return 0;
}

使用头文件utility中声明的函数std::move可以将对象的类型强制转换成右值引用,注意,记得将右值引用所指向的对象中使用了动态开辟内存的指针置空,否则该对象调用析构函数的时候将会回收这个已经让出去的内存空间。

编译器会自动生成那6个特殊的成员函数?
1. 默认构造函数

2. 默认析构函数

3.  默认复制构造函数

4.  默认赋值运算符

5. 移动构造函数

6. 移动赋值运算符

一旦你定义了移动构造函数或者移动赋值运算符,编译器将不再自动生成默认构造函数,默认复制构造函数,默认赋值运算符,因为编译器会认为你会完全管理资源,因此不再自动生成这些特殊的成员函数,反之,如果用户定义了构造函数,复制构造函数,以及赋值运算符中任意一个,都不会再自动生成移动构造函数,移动赋值运算符。

        需要注意的是复制构造函数和移动构造函数的参数是不同的,移动构造函数传入的不仅仅是右值引用,而且是没有const的,而复制构造函数带有const,原因是移动构造函数会更改传入的临时对象(或者右值)的指针,让其指向的内存转让给其他对象,然后自己指向空指针,这样才能完成空间的转让。

在上述情况下,如果仍然想让编译器自动生成相应的构造函数,可以在声明构造函数的后面加上default

如:
 

class MyClass
{
    
public:
    MyClass(MyClass &&mc);//一般来说定义了移动构造函数后,程序将不会自动生成复制构造函数
    MyClass(const MyClass &mc) = default;//显示得让程序生成复制构造函数
}

与default相对应得关键词是delete,使用delete可以禁止编译器使用特定的方法,即禁止某个函数的使用。

class MyClass
{
    
public:
    MyClass(MyClass &&mc);
    MyClass(const MyClass &mc) = delete;//禁止使用复制构造函数
}

什么是继承构造函数?

继承构造函数即为派生类构造函数直接继承基类的构造函数。

一般来说,构造函数,析构函数,赋值运算符,取地址运算符以及私有成员函数是派生了无法继承的,如果像继承基类的构造函数,则可以使用using来让派生类继承基类的所有构造函数,使用这种方法一般是因为基类的构造函数比较完整,用基类的构造函数就可以完成初始化,这样就可以省去重新定义一个和基类构造函数干相同事情的操作,即使用基类的构造函数却可以创造一个派生类的对象,我们一般说的构造函数无法继承的意思是说无法用基类的构造函数直接创建一个派生类的对象。

举个例子:

// 基类
class Base {
public:
    Base(int val) : value(val) {
        cout << "Base constructor called with value: " << value << endl;
    }

private:
    int value;
};

// 派生类
class Derived : public Base {
public:
    using Base::Base; // 使用基类的构造函数(继承构造函数)
};

int main() {
    Derived d(10); // 直接调用基类的构造函数
    return 0;
}
//派生类没有自己的成员变量,只有基类的构造函数即可完成初始化,使用继承构造函数就不需要自己定义构造函数了
//如果没有使用继承构造函数则需要定义一个调用基类构造函数的派生类构造函数
//Derived(int val) : Base(val) {} 

重新定义将隐藏方法是什么意思?
        意思就是说派生类如果定义了一个和基类方法同名的方法(不考虑参数,只考虑名字),这时候编译器将会只使用派生类的该方法而继承而来的同名方法将会被隐藏(覆盖),这样的现象就叫做"重新定义将隐藏方法"。

如果我像重新定义一个同名方法但却不想隐藏基类的方法应该怎么办?

class Derived : public Base
{
public:
    using Base::foo; // Unhide Base::foo(int x)
    void foo()
    {
        // ...
    }
//这个时候派生类中将有两个foo方法,一个是继承而来的基类方法foo,一个是自定义的foo
};

使用using既可将继承而来的基类方法显现而不会隐藏,这个时候就会根据参数的类型来调用不同版本的foo,传入int类型的参数就调用基类的方法,无参数就调用派生类的同名方法。

重载和重写以及重新定义有什么区别?

1.重载是在一个作用域内进行的,多定义几个参数列表(参数类型和参数个数以及返回值)不同但同名方法,这种叫做重载。重载通常发生在一个类内。

如:
 

   class Demo {
       void func() { ... }
       void func(int a) { ... }
       void func(double a, int b) { ... }
   }

2.

重写指的是派生类重写基类的方法,更改方法的行为,需要注意的是重写基类的方法要求派生类的方法必须与基类的方法具有完全相同的方法名以及参数列表,这时候如果通过派生类对象调用派生类方法的时候将会调用派生类的方法而不是基类的方法。

 3.

重新定义,我们知道重新定义将隐藏方法,在派生类重新定义方法有点像重载,但是重载一般发生在一个类中而且不要求像重写一样参数列表和函数名都相同,而这里的重新定义发生在派生类中,此时派生类将隐藏基类的同名方法,而只使用派生类重新定义的同名方法。

        这就是这三种的区别。

介绍两个关键词override和final

override用于派生类重写基类的方法,记住是重写,重写要求方法名和参数列表都必须相同,使用override是为了检查派生类重写格式是否有误。

final

final有两个作用,一是阻止类的进一步继承。二是阻止方法的进一步重写,但是重新定义是可以通过编译的。

如:

#include <iostream>
using namespace std;
class MyClass 
{
	public:
		virtual void fuc() final{cout << "Base " << endl;}
};

class Derive : public MyClass
{
	public:	
		void fuc() {cout << "Derive" << endl;}
		
};

int main(void)
{
	return 0;
}

这样编译是不会通过的,你这样相当于重写,派生类将基类的方法重写了。

但是重新定义是没有问题的

#include <iostream>
using namespace std;
class MyClass 
{
	public:
		virtual void fuc() final{cout << "Base " << endl;}
};

class Derive : public MyClass
{
	public:	
		void fuc(int n) {cout << "Derive" << endl;}
		
};

int main(void)
{
	Derive temp;
	temp.fuc(10);
	return 0;
}

重新定义将隐藏方法,即基类的方法将会被隐藏
 

Lambda函数

先回顾和介绍三种表达式for_each,count_if, generate

for_each(, ,)

第一个和第二个参数都是迭代器,第三个参数是要执行的操作,可以是函数指针,函数符或者是lambda函数,该表达式的作用就是遍历容器,执行操作。

count_if(,,)

第一个参数和第二个参数都是迭代器,第三个参数是要执行的操作,可以是函数指针,函数符或者是lambda函数,返回值要为bool类型,如果是true则计数+1,如果是false则计数-1,整个表达式的返回值是个整数,即计数值。

generate(,,)

第一个参数和第二个参数都是迭代器,第一个参数和第二个参数都是迭代器,第三个参数是要执行的操作,可以是函数指针,函数符或者是lambda函数,返回值要为容器所容纳的数据类型,该表达式的作用是填充容器的值;

#include <cstdlib>
#include <ctime>
#include <vector>
#incldue <algorithm>

//generate的使用:
srand(time(0));//产生随机数种子
int SIZE = 10;
vector<int > v(SIZE);
generate(v.begin(), v.end(), rand);//用随机数来填充vector

//count_if的使用:
bool countNum(int n)
{
    return n % 3 == 0;
}
int count = count_if(v.begin(), v.end(), countNum);

//for_each的使用:

void Show(int n)
{
    cout << n << endl;
}
for_each(v.begin(), v.end(), Show);

那什么是lambda函数呢?

lambda函数也叫做匿名函数,可以认为lambda函数就是一个小的函数,它是用来简化代码的一种方式。

形如:
 

[](int n)
{
    return n % 3 == 0;
}

lambda函数不用定义返回类型,其返回类型是使用decltype来决定的,也无需定义函数名。

[]是捕获列表,lambda函数可以访问作用域内的任何动态变量,而捕获列表指定(限制)了lambda函数可以访问所在作用域的那些变量和如何访问。

以下是一些常用的捕获方式:

  1. []:不捕获任何变量。

  2. [x][=]:按值捕获,创建x的一个新副本(不论x是值类型还是引用类型都只复制对象的值)。

  3. [&x][&]:按引用捕获,创建x的一个引用,可以改变x的值。

  4. [this]:捕获当前类的this指针,用于在lambda中访问类的成员。

  5. [x, &y]:混合捕获,可以同时捕获一些变量的副本和一些变量的引用

例子:

#include <iostream>
int main()
{
    int val = 1;
    auto copy_val = [val] { return val; };
    val = 100;
    auto stored_val = copy_val();
    std::cout << "stored_val: " << stored_val << std::endl; // 输出: stored_val: 1
    std::cout << "val: " << val << std::endl; //输出: val: 100

    int val_ref = 1;
    auto copy_ref = [&val_ref] { return val_ref; };
    val_ref = 100;
    auto stored_val_ref = copy_ref();
    std::cout << "stored_val_ref: " << stored_val_ref << std::endl; // 输出: stored_val_ref: 100
    std::cout << "val_ref: " << val_ref << std::endl; //输出: val_ref: 100
    return 0;
}

lambda函数也是可以有名字的,当lambda函数多次出现的时候,应该给lambda一个名字,简化代码,而不是用一次就定义一次,举个例子:

auto Add = [](int x, int y) {return x+y;}
//让lamb函数的名字确定为Add
int num = Add(5, 3);

包装器

包装器头文件functional下的一个模板类,可以用来优化程序,包装器可以接收函数,函数指针,函数对象以及lambda函数作为参数来初始化。

那么包装器有什么用呢?
用来优化程序,提高资源的利用率,比如说让模板类的实例化次数降低。

怎么做到的?

先看代码,下面解释。

#include <functional>
function<double(double) > ef = fuc;
//包装器ef可以接收一个参数是double且返回值为double的函数,函数指针,函数对象或者lambda函数
template<class T, class U>
T Fuction(T t, U u)
{
    return U(t);
};
//用包装器作为模板函数的参数,这样模板函数只会被实例化一次,因为我们传入的是包装器



        如果T的类型为double,函数,函数指针,函数对象,lambda函数作为参数U传入到模板类中,因为其类型不一样,所以U的类型的类型也不一样,导致模板类被实例化了4次。
但实际上可以使用一种方法来让模板类的实例化变为1次,那就是将特征标(参数列表和返回类型)相同的函数,函数指针,函数对象,以及lambda函数都封装成一种类型,这样U就是传入这种封装的类型,而不是分别传这4种类型,这样模板类就只会被实例化一次,第一个参数类型是double,而第二个参数类型是包装器。

        所以包装器就是一种封装手段,将特征标相同的函数,函数指针,函数对象以及lambda函数都看作为一种类型。

可变参数模板

可变参数模板是c++11推出的一种模板类,该模板类不限制类型参数的个数

下面是如何使用可变参数模板:

template<class T>//函数参数包中只剩一个参数的时候调用该模板函数,进行结束操作
void Show_List(T t)
{
    cout << t << endl;
}

template<class T, class...Args>//模板参数包,里面包的是传入的参数类型
void Show_List(T t, Args...args)//函数参数包,里面包的是传入的值
{
    cout << t << " ";
    Show_List(args...);//使用递归的方式来使用模板参数包里面的内容,相当于出栈,出栈后对栈剩下的部分再进行一次函数调用,直到只剩一个的时候再进行结束操作;

}

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

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

相关文章

【MySQL系列 05】Schema 与数据类型优化

良好的数据库 schema 设计和合理的数据类型选择是 SQL 获得高性能的基石。 一、选择优化的数据类型 MySQL 支持的数据类型非常多&#xff0c;选择正确的数据类型对于获得高性能至关重要。不管存储哪种类型的数据&#xff0c;下面几个简单的原则都有助于做出更好的选择。 1. …

AOP-注解实现-记录日志到数据库

概念解释 AOP&#xff1a;Aspect Oriented Programming Aspect&#xff1a;方面Oriented&#xff1a;面向…的Programming编程 之前我对模块化编程的认识&#xff0c;主要是局限在布局结构、目录结构上。比如Vue的template模板。 对方法的模块化编程&#xff0c;我之前的认识…

基于springboot+layui仓库管理系统设计和实现

基于 java springbootlayui仓库管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取…

硬件工程师面试题梳理-百度硬件面试题

硬件工程师基本职责 在公司里面&#xff0c;硬件工程师的主要职责包括设计、开发和测试硬件系统&#xff0c;以满足产品需求和性能要求。他们负责确保硬件系统的可靠性、稳定性和可维护性&#xff0c;并与软件工程师和其他团队成员合作&#xff0c;以确保硬件和软件的协同工作…

arcgis辅助下的GIS滑坡泥石流易发性评估模型构建

我国是地质灾害多发国家&#xff0c;地质灾害的发生无论是对于地质环境还是人类生命财产的安全都会带来较大的威胁&#xff0c;因此需要开展地质灾害风险普查。利用遥感&#xff08;RS&#xff09;技术进行地质灾害调查工作具有宏观、快速、准确的特点&#xff0c;能反映出地质…

SpringCloud(21)之SpringCloud Alibaba Nacos实战应用

一、Nacos安装 1.1 Nacos概述 Nacos是Alibaba微服务生态组件中的重要组件之一&#xff0c;主要用它实现应用的动态服务发现、配置管理、 服务管理。Nacos discovery alibaba/spring-cloud-alibaba Wiki GitHub Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简…

MotionCtrl: A Unified and Flexible Motion Controller for Video Generation

MotionCtrl: A Unified and Flexible Motion Controller for Video Generation 这篇论文是基于VideoCrafter的&#xff0c;而VideoCrafter是基于LVDM的 关于LVDM可以看https://blog.csdn.net/Are_you_ready/article/details/136615853 2023年12月6日发表在arxiv 这篇论文讨论…

seo js转码工具

js转码工具作用 用于把js加密 如果不想让别人看到自己的js 代码就可以使用这个方法 js工具网址 https://tool.chinaz.com/js.aspx 效果

J.K.罗琳创作的《神奇动物》系列电影赏析

故事情节 《神奇动物在哪里》&#xff1a; 这部电影讲述了纽特斯卡曼德来到纽约的故事&#xff0c;他是一位收集和研究魔法动物的巫师。在纽约&#xff0c;他的一只神奇生物逃脱&#xff0c;并引发了一系列麻烦。与此同时&#xff0c;纽约巫师社会面临着黑暗力量的威胁&#x…

超大规模-近场

这里先了解基站到用户的&#xff0c;无RIS的近场模型 超大规模智能反射面辅助的近场移动通信研究 &#xff08;论文题目&#xff09; &#xff08;期刊&#xff09;无线电通信技术 系统&#xff1a;BS-RIS-UE&#xff0c;两个阶段都是近场 模型&#xff1a;球面波传播模型&…

在dpvs上实现ICMP的源进源出

目录 1. 缘起2. 源码分析3. 让ICMP也走源进源出1. 缘起 在网络通信中,当一个请求报文从源主机到达目标主机,并经过中间路由器或交换机进行转发时,请求报文进入主机A的路径和响应报文离开主机A的路径可能不同。这种情况下,就会出现所谓的三角路径问题。如下图: 具体来说,…

USB协议学习(三)大容量存储设备SCSI协议分析

笔者来简单介绍一下SCSI得协议命令 1、SCSI协议认识 SCSI&#xff1a;Small Computer System Interface&#xff0c;用于计算机外部设备得接口标准&#xff0c;定义了与外部设备得一套协议。SCSI标准协议族支持很多钟SCSI设备&#xff0c;像盘&#xff0c;打印机&#xff0c;扫…

论企业安全漏洞扫描的重要性

前言 随着信息技术的迅猛发展和互联网的广泛普及&#xff0c;网络安全问题日益凸显。在这个数字化的世界里&#xff0c;无论是企业还是个人&#xff0c;都面临着前所未有的安全威胁。安全漏洞&#xff0c;作为这些威胁的源头&#xff0c;常常被忽视或无法及时发现。 而安全漏洞…

提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C++风格字符串完成

#include <iostream> #include <array> using namespace std;int main() {cout<<"请输入一个字符串"<<endl;//array<string,100> str;string str;getline(cin,str);int daxie0,xiaoxie0,num0,space0,other0;int lenstr.size();;for(in…

植物病害识别:YOLO水稻病害识别数据集(11000多张,yolo标注)

YOLO水稻病害识别数据集&#xff0c;包含叶斑病&#xff0c;褐斑病&#xff0c;细菌性枯萎病&#xff0c;东格鲁病毒病4个常见病害类别&#xff0c;共11000多张图像&#xff0c;yolo标注完整&#xff0c;可直接训练。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c…

Flink 性能优化总结(反压优化篇)

反压的理解 Flink 中每个节点间的数据都以阻塞队列的方式传输&#xff0c;下游来不及消费导致队列被占满后&#xff0c;上游的生产也会被阻塞&#xff0c;最终导致数据源的摄入被阻塞。简单来说就是系统接收数据的速率远高于它处理数据的速率。 反压如果不能得到正确的处理&am…

软件测试面试需要准备什么?面试有什么技巧?看完面试轻松解决

前言 无论是在校招还是社会企业招聘中&#xff0c;应聘者总是要经过层层的考核才能被聘用。然而&#xff0c;在招聘时&#xff0c;设置的编程以及非技术面试问题&#xff0c;真的有必要吗&#xff1f;如此就能考核出一位开发者的真实水平&#xff1f; 说到底就是考验你的技术以…

分享10个ai人工智能ppt生成软件,一键轻松搞定PPT制作!

ai 人工智能发展至今&#xff0c;已经诞生了各式各样的 AI 软件&#xff0c;最常见的如 AI 写作软件、AI 绘画软件、AI 人工智能 ppt 生成器、AI 人工智能抠图软件等等。对每天要面对各类文档、演示文稿&#xff08;PPT&#xff09;的职场人来说&#xff0c;最被需要的 AI 软件…

javascript:void(0);用法及常见问题解析

在Web开发中&#xff0c;javascript:void(0);是一个经常被用到的代码片段&#xff0c;特别是在一些老式的网页中。这个代码片段的作用是执行一个空操作&#xff08;null operation&#xff09;&#xff0c;即不执行任何操作。它的主要用途是在JavaScript代码中创建一个空链接&a…

AHU 汇编 实验二

一、实验名称&#xff1a;实验二 不同寻址方式的灵活运用 二、实验内容&#xff1a;定义数组a[6]&#xff0c;用多种寻址方式访问对应元素&#xff0c;实现&#xff08;a[0]a[1]&#xff09;*(a[2]-a[3])/a[4],将结果保存在内存a[5]中&#xff0c;用debug查询结果。 实验过程&a…