C++新经典 | 记录在最后的高阶知识点

news2024/9/27 9:27:00

目录

一、函数调用运算符与function类模板

1.函数调用运算符

(1)函数类型

(2)可调用对象

2.function类模板

二、万能引用类型

1.万能引用

2.万能引用资格的剥夺与辨认

(1)const修饰词

(2)类模板成员函数

三、引用折叠

1.编译器合并&的规则

四、std::forward及std::move

1.完美转发std::forward

2.std::move VS std::forward

五、auto类型

1.auto的特点

2.auto类型推断

(1)传值方式(非指针,非引用)

(2)指针或者引用类型但不是万能引用

(3)万能引用类型

3.auto类型std::initializer_list的特殊推断

六、decltype

七、std::function & std::bind

1.详细记录

2.简单说明

八、lambda表达式

1.lambda表达式的特点

2.格式说明

3.捕获列表说明


一、函数调用运算符与function类模板

1.函数调用运算符

        函数调用总离不开一对圆括号,“()”就是函数调用的一个明显标记,这个“()”有一个称呼叫函数调用运算符。

int Add(int value)
{
    return value + 1;
}

        如果在类中重载了这个函数调用运算符“()”,就可以像使用函数一样使用该类的对象,或者换句话说就可以像函数调用一样来“调用”该类的对象。写出来这个函数调用运算符后,怎样使用呢?分两步使用即可:

(1)定义一个该类的对象。

(2)像函数调用一样使用该对象,也就是在“()”中增加实参列表。

class TestOperator {
public:
    int operator()(int value) const    //重载函数调用运算符
    {
        return value + 1;
    }
};
void main()
{
    TestOperator test;
    std::cout << test(5) << std::endl; //6
}

        Add函数以及TestOperator类中重载的函数调用运算符,它们的形参和返回值是相同的,这就叫作“调用形式相同” 。

        一种调用形式对应一个函数类型,所以因为Add函数以及TestOperator类中重载的函数调用运算符调用形式相同,所以它们函数类型相同。

(1)函数类型

int(int)

        上面这行代表一个“函数类型”:接收一个int参数,返回一个int值。

(2)可调用对象

        “可调用对象”这个概念(“函数对象”“仿函数”都是同一个意思),那么如下两个都是可调用对象:

  • Add函数。
  • 重载了函数调用运算符“()”的TestOperator类所生成的对象。

2.function类模板

        C++11中,标准库里有一个叫作function的类模板,这个类模板是用来包装一个可调用对象的。要使用这个类模板,当然是要提供相应的模板参数,这个模板参数就是指该function类型能够表示(包装)的可调用对象的调用形式:

function<int(int)>

        上面这种写法是一个类类型(类名就是function<int(int)>),用来代表(包装)一个可调用对象,它所代表的这个可调用对象接收一个int参数,返回一个int值。

        如果上面的Add函数有一个重载,那么就无法包装进function中。这也是一个二义性导致的问题,那么这个问题怎样解决?可以通过定义一个函数指针来解决,因为函数指针中含有参数类型和返回类型。

int Add(int value)
{
    return value + 1;
}
int Add(int value1,int value2)
{
    return value1 + value2;
}
void main()
{
    int(*p)(int)= Add;                    //定义一个函数指针p,不会产生二义性。因为函数指针中含有参数类型和返回类型。
    std::function<int(int)> fun = p;
    std::cout << fun(5) << std::endl;     //6

    int(*p1)(int,int)= Add;    
    std::function<int(int,int)> fun1 = p1;
    std::cout << fun1(5,6) << std::endl;  //11
}

二、万能引用类型

        universal reference(后来被称为forwarding reference:转发引用)翻译成中文有好几种翻译方法,取两种最常见的翻译,一种叫“万能引用”,一种叫“未定义引用”,都是一个意思,后续就称为“万能引用”了。

1.万能引用

        万能引用是一种类型。就跟int是一种类型一个道理,再次强调,万能引用是一种类型。

        万能引用(又名未定义引用,英文名universal reference)离不开两种语境,这两种语境必须同时存在:

  • 必须是函数模板。
  • 必须是发生了模板类型推断并且函数模板形参长这样:T&&。
void Test(int&& data)  //形参是一个右值引用,实参需要一个右值
{
    std::cout << data << std::endl;
}
void main()
{
    int i = 10;
    Test(i);//错误,i是左值,而参数需要一个右值
}
template <typename T>
void Test(T&& data) //T&&万能引用,参数既可以支持左值,也可以是右值
{
    std::cout << data << std::endl;
}
void main()
{
    int i = 10;
    Test(i);        //正确
}

        万能引用就长这样:T&&(T必须与&&挨着)。它也用两个地址符号“&&”表示,所以万能引用长得跟右值引用一模一样。但是解释起来却不一样(注意语境,只有在语境满足的条件下,才能把“&&”往万能引用而不是往右值引用解释):

(1)右值引用作为函数形参时,实参必须传递右值进去,不然编译器报错,上面已经看到了。

(2)而万能引用作为函数形参时,实参可以传递左值进去,也可以传递右值进去。所以,万能引用也被人叫作未定义引用。如果传递左值进去,那么这个万能引用就是一个左值引用;如果传递右值进去,那么这个万能引用就是一个右值引用。从这个角度来讲,万能引用更厉害:是一种中性的引用,可以摇身一变,变成左值引用,也可以摇身一变,变成右值引用。

T&&才是万能引用,千万不要理解成T是万能引用,其实,data的类型是T&&,所以data的类型才是万能引用类型(或者理解成data才是万能引用),这意味着如果传递一个整型左值进去,data的类型最终就应该被推断成int&类型;如果传递一个整型右值进去,data最终就应该被推断成int&&类型。

 下面的两种情况才是万能引用,其他的看到的“&&”的情况都是右值引用:

  • 一个是函数模板中用作函数参数的类型推断(参数中要涉及类型推断),形如T&&。
  • auto&& tmpvalue=…也是一个万能引用。

2.万能引用资格的剥夺与辨认

(1)const修饰词

        const修饰词会剥夺一个引用成为万能引用的资格,被打回原形成右值引用。T&&前后左右都不要加什么修饰符,不然很可能就不是万能引用而直接退化为右值引用了。

template <typename T>
void Test1(const T&& data) //const修饰词会剥夺一个引用成为万能引用的资格,被打回原形成为右值引用。
{
    std::cout << data << std::endl;
}
void main()
{
    int i = 10;
    Test1(i);//错误,i是左值,而参数需要一个右值
}

(2)类模板成员函数

        如下方代码Test3后面的T&&不是一个万能引用,而是一个右值引用。因为Test3成员函数本身没有涉及类型推断,Test3成员函数是类模板TEST的一部分。

template <typename T>
class TEST {
public:
    void Test3(T&& data)//T&&不是万能引用,实参需要一个右值
    {
        std::cout << data << std::endl;
    }
};

        如果搞不清楚形参类型是否是一个万能引用,则分别传递进去一个左值和一个右值作为实参来调用,就可以验证。


三、引用折叠

        引用折叠是一个C++11新标准里出现的概念,同时也是一条规则,英文名字是reference-collapsing rules(引用折叠规则),有人也翻译成引用坍塌,都是一个意思。想一想,“折叠”这个词,从字面分析,就是给鼓捣没一些东西或者折起来一些东西,这里三个&就给鼓捣剩1个了,这就是引用折叠规则的体现。

        在C++中,有明确含义的“引用”只有两种,一种是带一个&的左值引用,一种是带两个&&的右值引用。但是,此时此刻竟然出来三个&(&&&),并且这三个&应该是第一个一组,后两个一组,也就是& &&这种感觉。

        第一组是一个左值引用,第二组因为已经实例化过了,所以第二组的两个&&就不可能再是万能引用了,所以第二组的两个&&实际是右值引用。现在编译器遇到超过两个&了,第一组一个&,第二组两个&&,编译器就会把超出两个的&合并,实际上合并的原因不仅仅是因为超过两个&,只要是左值之间相遇、左值和右值相遇、右值之间相遇,以及右值和左值相遇,系统都会进行&符号的合并,合并后的&数量肯定比合并之前少,所以才叫“折叠”嘛!

        写程序的时候不能写出三个&&&,否则是语法错误。

template <typename T>
void Test(T&& data) //T&&万能引用,参数既可以支持左值,也可以是右值
{
    std::cout << data << std::endl;
}
void main()
{
    int a = 10;
    int& b = a;
    Test(b);
}

1.编译器合并&的规则

        左值引用是一个&表示,右值引用是两个&&表示,如果任意一个引用为左值引用,结果就为左值引用(左值引用会传染),否则结果为右值引用。所以这两种引用组合一下就会有四种可能的组合:

  • 左值&-左值&:左值引用&
  • 左值&-右值&&(这是上面范例当前的情形):左值引用&
  • 右值&&-左值&:左值引用&
  • 右值&&-右值&&:右值引用&& 

四、std::forward及std::move

        注意:形参总是左值,即使其类型是右值引用。如下代码:num是一个左值,但它的类型是右值引用。

void Function(int&& num)
{
}

        对于一个变量: 

  • 如果从左值还是右值这个概念/角度来讲,它要么是左值,要么是右值,不可能是其他东西。当这个变量作为实参传递给某个函数的形参时,如果这个变量是左值,那么这个函数的形参必须得是一个左值引用;如果这个变量是右值,那么这个函数的形参必须得是一个右值引用。否则就会报语法错。
  • 如果从类型这个概念/角度来讲,它要么是一个左值引用,要么是一个右值引用(万能引用不算,因为万能引用只出现在类型推导中,不在讨论范围之内)。它到底是左值引用还是右值引用,看它是怎样定义的。如果它这样定义:“int &ta …;”,显然,ta是一个左值引用,如果它这样定义:“int &&ta…;”,显然,ta是一个右值引用。所以左值引用只能绑到一个左值上去(例如左值引用作函数形参时,实参只能是左值),右值引用只能绑到一个右值上去(例如右值引用作函数形参时,实参只能是右值)。
template <typename F,typename T1,typename T2>
void Test(F fun,T1&& data1,T2&& data2)    //data1和data2都是万能引用类型,那么从实参中来的左值或者右值信息、const信息就都会保存在data1和data2参数中
{                                         
    //fun(data1, data2);//报错  无法将参数 1 从“T1”转换为“int &&” ,因为data1和data2都是左值,而Function的第一个参数需要一个右值

    fun(std::forward<T1>(data1), std::forward<T2>(data2));
}

void Function(int&& num1, int& num2) //第一个参数需要右值,第二个参数需要左值;num1的类型是右值引用,但num1本身是左值 ;右值引用作函数形参时,实参只能是右值
{
    std::cout << num1<<","<<num2 << std::endl;
}
void main()
{
    int num2 = 20;
    Test(Function,10, num2);   //10是右值,num是左值
}

        有个实参是一个值(10),传递到一个函数模板(Test)中之后,这个模板中有个形参(data1),专门接这个右值,所以这个形参是一个右值引用,但是这个形参本身是一个左值。试想,原来是一个右值,接收到后变成了左值,那如果另外一个函数(Function的num1参数)正好需要一个右值绑定过来,那就得把这个左值再变回右值去,这就用到std::forward函数。

        注意:万能引用中,给一个int类型的左值,T推导出来的类型为int &;给一个int类型的右值,T推导出来的类型为int。即:T1是int类型,T2是int&类型。当T推导为int &类型时还发生了引用折叠。

1.完美转发std::forward

        完美转发比较好地解决了参数转发的问题,通过一个函数模板,可以把任意的函数名、任意类型参数(只要参数个数是确定的)传递给这个函数模板,从而达到间接调用任意函数的目的。std::forward的能力就是保持原始实参的左值或者右值性。

        对这个函数有两种理解:

  • 实参原来是一个左值(j),到了形参中还是左值(data2)。forward能够转化回原来该实参的左值或者右值性,所以std::forward之后还是一个左值。
  • 实参原来是一个右值(10),到了形参中变成了左值(data1)。forward能够转化回原来该实参的左值或者右值性,所以std::forward之后还是一个右值。

        所以,从现在的情形看,forward有强制把左值转成右值的能力。所以,看起来std::forward这个函数只对原来是一个右值这种情况有用。

        回顾上述代码:“Test(Function,10, num2);”,这里的10本来是一个右值,到了void Test(F fun,T1&& data1,T2&& data2)里面去之后,向Funciton转发的时候“fun(data1, data2);”中的data1变成了一个左值,是std::forward使它恢复了右值身份:std::forward<T1>(data1),所以这里可以把forward看成是强制把一个左值转换成了一个右值。

        std::forward就是通过“<>”里面的类型决定把变量转成左值还是右值,当forward的尖括号里是int时,表示转成右值;当forward的尖括号里是int&,表示转成左值。 

2.std::move VS std::forward

  • std::move是属于无条件强制转换成右值(如果原来是左值,就强制转成右值;如果原来是右值,那就最好,保持右值不变)。std::forward是某种条件下执行强制转换。例如原来是右值,因为某些原因(如参数传递)被折腾成左值了,此时forward能转换回原来的类型(右值);如果原来是左值,那forward就什么也不干。
  • std::forward总感觉用起来方便性不够,因为既得为其提供一个模板类型参数,又要提供一个普通参数。而std::move只需要一个普通参数,不需要模板类型参数。
  • 从具体书写代码的角度谈:
    • std::move后面往往是接一个左值,std::move是把这个左值转成右值,转成右值的目的通常都是做对象移动(所以这个对象应该支持移动,前面讲过移动构造函数)的操作。不然平白无故地转成右值也没多大意义。
    • std::forward往往是用于参数转发,所以不难发现,std::forward后面圆括号中的内容往往都是一个万能引用(如std::forward<T>(t)中的t就是一个万能引用)。

五、auto类型

1.auto的特点

  • auto的自动类型推断发生在编译期间。
  • auto定义变量必须立即初始化,这样编译器才能推断出它的实际类型。编译的时候才能确定auto的类型和整个变量的类型,然后在编译期间就可以用真正的类型替换掉auto这个类型占位符。
  • auto的使用比较灵活,可以和指针、引用、const等限定符结合使用。
  • auto不能用于函数参数,如void myfunc(auto x,inty)不可以。
  • 非静态数据成员不能具有包含auto的类型。静态数据成员可以使用auto。

2.auto类型推断

(1)传值方式(非指针,非引用)

        传值方式针对auto类型:会抛弃引用、const等限定符。

    auto num = 10;          //num为int类型
    const auto num1 = num;  //num1为const int类型
    auto num2 = num1;       //num2为int类型,会抛弃const限定符

    const auto& num3 = num; //不属于传值方式。num3为const int&类型
    auto num4 = num3;       //属于传值方式。num4为int类型,会抛弃引用、const等限定符

(2)指针或者引用类型但不是万能引用

        指针或者引用方式针对auto类型:不会抛弃const限定符,但是会抛弃引用。

    auto num = 10;           //num为int类型
    auto &num1 = num;        //num1为int&类型
    const auto* num2 = &num; //num2为const int*类型
    auto num3 = num2;        //num3为const int*类型
    auto* num4 = &num1;      //num3为int*类型,会抛弃引用限定符

(3)万能引用类型

        和万能引用模板推理类似:给一个int类型的左值,auto推导出来的类型为int &;给一个int类型的右值,auto推导出来的类型为int。

3.auto类型std::initializer_list的特殊推断

        std::initializer_list也是C++11引入的一个新类型(类模板),表示某种特定类型的值的数组。当用auto定义变量并初始化时如果用“={}”括起来,则推导出来的类型就是std::initializer_list了。

        std::initializer_list其实是一个类模板,它包含一个类型模板参数用来表示其中的成员类型(也就是这个数组里面所保存的成员类型),这个成员的类型也需要推导(这是第二次推导),如果“{}”中的成员类型不一致,则成员类型的推导会失败。

    auto num = 10;                  //num为int类型
    auto num1 = { 10 };             //num1为std::initializer_list<int>类型
    auto num2 = { 10,20,30 };       //num1为std::initializer_list<int>类型
    //auto num3 = { 10,20,30.1f };  //错误,无法推导auto类型

        对象的初始化方式五花八门,有用“()”的,有用“{}”的,也有用“={}”的等。为了统一对象的初始化方式,在C++11中,引入了“统一初始化”的概念,英文名就是Uniform Initialization,试图努力创造一个统一的对象初始化方式 。

        当编译器看到这种大括号括起来的形如{"aa","bb","cc"}的内容,一般就会将其转化成一个std::initializer_list。所以可以这样认为,所谓的“统一初始化”,其背后就是std::initializer_list进行支持的。

六、decltype

        decltype和auto有类似之处,两者都是用来推断类型的。decltype有如下特点:

  • decltype的自动类型推断也发生在编译期,这一点和auto一样。
  • decltype不会真正计算表达式的值。
  • const限定符、引用属性等有可能会被auto抛弃,但decltype一般不会抛弃任何东西。

        固定规则:①decltype后面是一个非变量的表达式(*p);②且该表达式能够作为等号左边的内容(*p=20;);那么decltype得到的类型就是一个形如“类型名&”的左值引用类型:

    auto num = 10;
    int *p = &num;
    *p = 20;
    decltype(*p) num1 = num;     //num1为 int& 类型

        decltype((变量))的结果永远是引用。注意这里是双层括号。而decltype(变量),除非变量本身是引用,否则整个decltype的类型不会是引用。

decltype后的“()”里本来是一个变量,但如果这个变量名上额外加了一层括号或者多层括号,那编译器就会把这个变量当成一个表达式,又因为变量名可以放在等号左侧(左值),所以会推断出引用类型。

    auto num = 10;
    int temp = 30;
    decltype(num) num1 = 20;         //num1为 int 类型
    decltype((num)) num2 = temp;     //num2为 int& 类型
    int temp = 30;
    auto &num = temp;                //num为 int& 类型
    decltype(num) num1=temp;         //num1为 int& 类型

七、std::function & std::bind

1.详细记录

boost | 函数与回调(一)ref与bind_boost::bind ref-CSDN博客

【精选】boost | 函数与回调(二)function_function回调函数_烫青菜的博客-CSDN博客

2.简单说明

        std::bind能将对象以及相关的参数绑定到一起,绑定完后可以直接调用,也可以用std::function进行保存,在需要的时候调用。

        std::bind有两个意思:

  • 将可调用对象和参数绑定到一起,构成一个仿函数,所以可以直接调用。
  • 如果函数有多个参数,可以绑定部分参数,其他的参数在调用的时候指定。 

        因为有了占位符(placeholder)这种概念,所以std::bind的使用就变得非常灵活。可以直接绑定函数的所有参数,也可以仅绑定部分参数。

        绑定部分参数时,就需要通过std::placeholders来决定bind所在位置的参数将会属于调用发生时的第几个参数。

  • std::bind的思想实际上是一种延迟计算的思想,将可调用对象保存起来,然后在需要的时候再调用。
  • std::function一般要绑定一个可调用对象,类成员函数不能被绑定。而std::bind更加强大,成员函数、成员变量等都能绑定。现在通过std::function和std::bind的配合,所有的可调用对象都有了统一的操作方法。

八、lambda表达式

1.lambda表达式的特点

    [捕获列表](参数列表)->返回类型 {
        函数体;
    };
  • 它是一个匿名函数,也可以理解为可调用的代码单元或者是未命名的内联函数。
  • 它也有一个返回类型、一个参数列表、一个函数体。
  • 与函数不同的是,lambda表达式可以在函数内部定义(上面范例就是在main主函数中定义的lambda表达式),这个是常规函数做不到的。

2.格式说明

  • 返回类型是后置的这种语法(lambda表达式的返回类型必须后置,这是语法规定)。因为很多时候lambda表达式返回值非常明显,所以允许省略lambda表达式返回类型定义——“->返回类型”都省略了,编译器能够根据return语句自动推导出返回值类型。
  • 没有参数的时候,参数列表可以省略,甚至“()”也可以省略。
  • 捕获列表[]和函数体不能省略,必须时刻包含。
  • lambda表达式的调用方法和普通函数相同,都是使用“()”这种函数调用运算符。
  • lambda表达式可以不返回任何类型,不返回任何类型就是返回void。
  • 函数体末尾的分号不能省。

3.捕获列表说明

        lambda表达式通过捕获列表来捕获一定范围内的变量。捕获这个概念,只针对在创建lambda表达式的作用域内可见的非静态局部变量(包括形参)。即:捕获是不包括静态局部变量的,也就是说,静态局部变量不能被捕获,但是可以在lambda表达式中使用。另外,静态局部变量保存在静态存储区,它的有效期一直到程序结束。

  • []:不捕获任何变量。
  • [&]:捕获外部作用域中所有变量,并作为引用在函数体内使用。
  • [=]:捕获外部作用域中所有变量,并作为副本(按值)在函数中使用,也就是可以用它的值,但不能给它赋值。
  • [this]:一般用于类中,捕获当前类中this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了“&”或者“=”,则默认添加了此项(this项)。也就是说,捕获this的目的就是在lambda表达式中使用当前类的成员函数和成员变量。注意,针对成员变量,[this]或者[=]可以读取,但不可以修改。如果想修改,可以使用[&]。
  • 按值捕获和按引用捕获。
    • [变量名]:按值捕获(不能修改)变量名所代表的变量,同时不捕获其他变量。
    • [&变量名]:按引用捕获(可以修改)变量名代表的变量,同时不捕获其他变量。
    • 上面的变量名如果是多个,之间可以用逗号分隔。当然对于按引用捕获,多个变量名的情况下,每个变量名之前也都要带有&。
  • [=,&变量名]:按值捕获所有外部变量,但按引用捕获“&”中所指的变量(如果有多个要按引用捕获的变量,那么每个变量前都要增加“&”),这里“=”必须写在开头位置,开头这个位置表示“默认捕获方式”。也就是说,这个捕获列表第一个位置表示的是默认捕获方式(也叫隐式捕获方式),后续其他的都是显式捕获方式。
  • [&,变量名]:按引用捕获所有外部变量,但按值捕获变量名所代表的变量。这里这个“&”必须写在开头位置,开头这个位置表示“默认捕获方式”。
void main(){
   auto function= [](int a)->int{   //lambda表达式创建的匿名函数
       return ++a;
   };
   //或者写成:
   std::function<int(int)> function= [](int a)->int{  
       return ++a;
   };
   //或者写成:
   int(*function)(int)=[](int a)->int{  
       return ++a;
   };
   std::cout << function(10) << std::endl;
}

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

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

相关文章

人工智能基础_机器学习011_梯度下降概念_梯度下降步骤_函数与导函数求解最优解---人工智能工作笔记0051

然后我们来看一下梯度下降,这里先看一个叫 无约束最优化问题,,值得是从一个问题的所有可能的备选方案中选最优的方案, 我们的知道,我们的正态分布这里,正规的一个正态分布,还有我们的正规方程,他的这个x,是正规的,比如上面画的这个曲线,他的这个x,就是大于0的对吧,而现实生活…

Java反射调用ashx

这篇文章卡了大概一周&#xff0c;一个是没时间&#xff0c;只能带娃加锻炼间隙挤点时间&#xff0c;一个是碰到了问题卡住了。本篇实现反射调用ashx实现类的基础结构。 首先申明ashx的接口&#xff0c;所有的ashx实现类继承实现该接口的基类 package appcode; import java.i…

dbeaver查看表,解决证书报错current license is non-compliant for [jdbc]

http://localhost:9200/_license { “license” : { “status” : “active”, “uid” : “b91ae0e0-b04d-4e20-8730-cf0bca7b2035”, “type” : “basic”, “issue_date” : “2023-02-22T14:33:27.648Z”, “issue_date_in_millis” : 1677076407648, “max_nodes” : 10…

Leetcode 43. 字符串相乘 中等

题目 - 点击直达 1. 43. 字符串相乘 中等1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 思路一 做加法1. 思路分析2. 时间复杂度3. 代码实现 3. 思路二 做乘法1. 思路分析2. 时间复杂度3. 代码实现 1. 43. 字符串相乘 中等 1. 题目详情 给定两个以字符串形式表示的非负整…

react中的useState和useImmer的用法

文章目录 一、useState1. 更新基本类型数据2. 更新对象3. 更新嵌套对象4. 更新数组5.更新数组对象 二、Immer1. 什么是Immer2. 使用use-immer更新嵌套对象3. 使用useImmer更新数组内部的对象 一、useState react中文官网教程 1. 更新基本类型数据 在函数式组件中&#xff0c…

【多线程相关其二】进程与线程

进程vs线程 进程&#xff08;process&#xff09;指的是正在运行的程序的实例&#xff0c;即an instance of a computer that is being executed。用拆字法理解就是&#xff1a;进行中的程序。程序是一个没有生命的实体&#xff0c;只有处理器执行它的时候才能成为一个活动的实…

macOS 创建Flutter项目

参考在 macOS 上安装和配置 Flutter 开发环境 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 这个文档&#xff0c;配置好flutter的环境 编辑器可以选择vscode或者IDEA。 我这里以IDEA为例 打开 IDE 并选中 New Flutter Project。 选择 Flutter&#xff0c;验证 F…

长图切图怎么切

用PS的切片工具 切片工具——基于参考线的切片——ctrl&#xff0b;shift&#xff0b;s 过长的图片怎么切 ctrl&#xff0b;alt&#xff0b;i 查看图片的长宽看图片的长宽来切成两个板块&#xff08;尽量中间切成两半&#xff09;用选区工具选中下半部分的区域——在选完时不…

电脑系统d3dcompiler_47.dll丢失问题,多种详细解决方法推荐

d3dcompiler_47.dll是Direct3D编译器组件的一部分&#xff0c;它是Microsoft DirectX的一部分。DirectX是一套由微软开发的多媒体编程接口&#xff0c;用于游戏和多媒体应用的开发。d3dcompiler_47.dll文件主要用于对DirectX编译器的调用&#xff0c;它包含了Direct3D着色器编译…

【C++】map 和 set 的使用

目录 C中的键值对 关联式容器 set、multiset map、multimap STL的容器分为两类&#xff1a;序列是容器、关联式容器&#xff1b;序列式容器是线性的数据结构&#xff0c;只有存储元素的功能&#xff0c;且像vector、list等还可以指定插入位置&#xff1b;而关联式容器底层底…

C++核心编程之---类和对象---C++对象模型和this指针

目录 一、成员变量和成员函数分开存储 二、this指针 三、空指针访问成员函数 四、const修饰成员函数 常函数&#xff1a; 常对象&#xff1a; 一、成员变量和成员函数分开存储 在C中&#xff0c;类内的成员变量和成员分开存储 只有非静态成员变量才属于类的对象上 示例&…

计算机基础知识42

标签的分类和嵌套 1. 单标签&#xff1a; img br hr # <img /> 2. 双标签&#xff1a; a h p div # <a></a> 3. 按照标签属性分类&#xff1a; 块儿标签&#xff1a; 自己独自占一行 # h1-h6 p div 行内(内联)…

2023高德地图poi资源下载

全国8千万地图poi地图数据&#xff1a;含名称、地址、电话、省份、城市、区县、经纬度、电话等信息

笔记47:FCN网络的Pytorch实现

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\1.语义分割任务\Pytorch中FCN的实现 a a a

数据结构——线性表②(链表)

《数据结构——线性表①&#xff08;顺序表&#xff09;》一文中已经讲了线性表顺序存储–顺序表相关内容&#xff0c; 这篇文章一起来学习 线性表的链式存储–链表↓↓↓↓↓ 一、链表的定义 线性表的链式存储称为链表&#xff0c;那什么是链式存储呢 其实理解起来就和火车差…

Jetpack:023-Jetpack中的事件二

文章目录 1. 知识回顾2. 使用方法2.1 单击事件2.2 双击事件2.3 长按事件2.4 滑动事件 3. 示例代码4. 内容总结 我们在上一章回中介绍了 Jetpack中事件相关的内容&#xff0c;本章回中继续介绍这方面的内容。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01;…

【Java数据结构重点知识】第一节:认识数据结构与算法、集合框架

一&#xff1a;数据结构与算法 1.数据结构 数据结构是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素的集合 2.算法 算法就是定义良好的计算过程。他取一个或一组的值为输入&#xff0c;并产生一个或一组作为输出。简单来说就是一系列的…

Linux】centos安装配置及远程连接工具的使用

【Linux】centos安装配置及远程连接工具的使用 1.使用vmware创建虚拟机&#xff0c;因为过程比较简单就没有截图了&#xff0c;根据下面步骤来就行。2.网络配置3.MobaXterm连接CentOS1.new session2.点击ssh&#xff0c;输入虚拟机的IP地址即可 4.进行阿里云换源1.进入2.下载wg…

AMD:抢占AI芯片宝座

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;AMD受益于AI芯片的出口限制&#xff0c;使其能够获得更多的中国市场份额&#xff0c;并增强其在AI芯片市场的地位。 &#xff08;2&#xff09;AMD的处理器&#xff0c;特别是E…

ctfshow-web入门命令执行29-36

29 源代码给了禁用flag 使用tac、nl ?cecho nl f*; ?cecho tac f*; 30 多禁用了system和php 和上题区别不大&#xff0c;使用上一题命令就能解 ?cecho nl f*; ?cecho tac f*; 31 禁用了空格使用%09代替 ?cecho%09tac%09f*; 32 禁用了echo 使用php伪协议 ?cinclud…