【C++】列表初始化声明范围forSTL容器新变化

news2024/11/18 11:29:01

文章目录

  • 什么是C++11
  • 列表初始化
    • **C++98中{}的初始化**
    • 内置类型的列表初始化
  • 关于initializer_list
    • 使用场景:
  • 声明
    • auto-变量类型推导
    • decltype类型推导
    • nullptr
  • 范围for
  • STL的新变化
    • 新容器:
    • 容器中的一些新方法

什么是C++11

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称,不过由于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能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率

关于C++11新特性: https://en.cppreference.com/w/cpp/11

小故事: 1998年是C++标准委员会成立的第一年,本来计划以后每5年视实际需要更新一次标准,C++国际标准委员会研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初这个标准叫C++ 07,但是到06年的时候,官方觉得2007年肯定完不成C++ 07,而且官方觉得2008年可能也完不成,最后干脆叫C++ 0x,x的意思是不知道到底能在07还是08还是09年完成,结果2010年的时候也没完成,最后在2011年终于完成了C++标准,所以最终定名为C++11


列表初始化

C++98中{}的初始化

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

struct Point
{
    int _x;
    int _y;
};
int main()
{
    int arr[] = {1,2,3,4,5};
    int array[5] = {0};
    Point p = { 1, 2 };
    //对于一些自定义的类型,却无法使用这样的初始化
    //例如:
    vector<int> v{1,2,3};//err,在C++98不能通过编译
    return 0;
}

导致每次定义vector时都需要先把vector定义出来,然后使用循环对其赋初始值,非常不方便


C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加

struct Point
{
	int _x;
	int _y;
};
int main()
{
	//使用大括号对内置类型进行初始化
	int x1 = { 1 }; //可添加等号
	int x2{ 2 };    //可不添加等号

	//使用大括号对数组元素进行初始化
	int array1[]{1, 2, 3, 4, 5}; //可不添加等号
	int array2[5]{0};            //可不添加等号

	//使用大括号对结构体元素进行初始化
	Point p{ 1, 2 }; //可不添加等号

	//C++11中列表初始化也可以用于new表达式中(C++98无法初始化)
	int* p1 = new int[4]{0};       //不可添加等号
	int* p2 = new int[4]{1,2,3,4}; //不可添加等号
	return 0;
}

注意: 用大括号对new表达式初始化时不能加等号.创建对象时也可以用列表初始化方式调用构造函数初始化

例子:

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()
{
	//一般调用构造函数创建对象的方式
	Date d1(2022, 8, 29);

	//C++11支持的列表初始化,这里也会调用构造函数初始化
	Date d2 = { 2022, 8, 30 }; //可添加等号
	Date d3{ 2022, 8, 31 };    //可不添加等号
	return 0;
}

内置类型的列表初始化

int main()
{
    //对于内置类型变量
    int x1 = {10};
    int x2{10};
    
    int x3 = 1+2;
    int x4 = {1+2};
    int x5{1+2};
    
    // 数组
    int arr1[5] {1,2,3,4,5};
    int arr2[]{1,2,3,4,5};
    // 动态数组,在C++98中不支持
    int* arr3 = new int[5]{1,2,3,4,5};
    // 标准容器
    vector<int> v{1,2,3,4,5};
    map<int, int> m{{1,1}, {2,2,},{3,3},{4,4}};
    return 0;
}

注意:列表初始化可以在{}之前使用等号,其效果与不使用=没有什么区别


关于initializer_list

文档介绍:http://www.cplusplus.com/reference/initializer_list/initializer_list/

C++11中新增了initializer_list容器,该容器没有提供过多的成员函数,提供了begin和end函数,用于支持迭代器遍历.以及size函数支持获取容器中的元素个数.

image-20221010164850280

注意:initializer_list是系统自定义的类模板

template<class T> class initializer_list;

initializer_list本质就是一个大括号括起来的列表,如果用auto关键字定义一个变量来接收一个大括号括起来的列表,然后以typeid(变量名).name()的方式查看该变量的类型,此时会发现该变量的类型就是initializer_list.

int main()
{
    auto il = { 10, 20, 30 };  // the type of il is an initializer_list
    cout << typeid(il).name()<<endl;//class std::initializer_list<int>
    for(auto e:il)
        cout << e<<" ";
    cout <<endl;
}

使用场景:

initializer_list容器没有提供对应的增删查改等接口,因为initializer_list并不是专门用于存储数据的,而是为了让其他容器支持列表初始化的

  • initializer_list一般是作为构造函数的参数 ·C++11对STL中的不少容器就增加initializer_list作为参数的构造函数,这样初始化容器对象就更方便了,也可以作为operator=的参数,这样就可以用大括号赋值

例子:

int main()
{
	//用大括号括起来的列表对容器进行初始化
	vector<int> v = { 1, 2, 3, 4, 5 };
	list<int> l = { 10, 20, 30, 40, 50 };
	vector<Date> vd = { Date(2022, 8, 29), Date{ 2022, 8, 30 }, { 2022, 8, 31 } };
	map<string, string> m{ make_pair("sort", "排序"), { "insert", "插入" } };
	//用大括号括起来的列表对容器赋值
	v = { 5, 4, 3, 2, 1 };
	return 0;
}

C++98并不支持直接用列表对容器进行初始化,这种初始化方式是在C++11引入initializer_list后才支持的,而这些容器之所以支持使用列表进行初始化,根本原因是因为C++11给这些容器都增加了一个构造函数,这个构造函数就是以initializer_list作为参数的.

多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数

image-20221010165203700

当用列表对容器进行初始化时,这个列表被识别成initializer_list类型,于是就会调用这个新增的构造函数对该容器进行初始化.

这个新增的构造函数要做的就是遍历initializer_list中的元素,然后将这些元素依次插入到要初始化的容器当中即可.,

例子:让模拟实现的vector也支持{}初始化和赋值,就需要增加一个以initializer_list作为参数的构造函数

namespace Mango
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		vector(initializer_list<T> il)
		{
			_start = new T[il.size()];
			_finish = _start;
			_endofstorage = _start + il.size();
			//迭代器遍历插入
			/*
			typename initializer_list<T>::iterator it = il.begin();
			while (it != il.end())
			{
				push_back(*it);
				it++;
			}
			*/
			//范围for遍历
			for (auto e : il)
			{
				push_back(e);
			}
		}
		vector<T>& operator=(initializer_list<T> il)
		{
			vector<T> tmp(il);
			std::swap(_start, tmp._start);
			std::swap(_finish, tmp._finish);
			std::swap(_endofstorage, tmp._endofstorage);
			return *this;
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};
}

说明一下:

  • 在构造函数中遍历initializer_list时可以使用迭代器遍历,也可以使用范围for遍历,因为范围for底层实际采用的就是迭代器方式遍历.
  • 使用迭代器方式遍历时,需要在迭代器类型前面加上typename关键字,指明这是一个类型名字.因为这个迭代器类型定义在一个类模板中,在该类模板未被实例化之前编译器是无法识别这个类型的.
  • 最好也增加一个以initializer_list作为参数的赋值运算符重载函数,以支持直接用列表对容器对象进行赋值,但实际也可以不增加.

如果没有增加以initializer_list作为参数的赋值运算符重载函数,下面的代码也可以正常执行:

vector<int> v = { 1, 2, 3, 4, 5 };
v = { 5, 4, 3, 2, 1 };
  • 对于第一行代码,就是调用以initializer_list作为参数的构造函数完成对象的初始化.
  • 而对于第二行代码,会先调用initializer_list作为参数的构造函数构造出一个vector对象,然后再调用vector原有的赋值运算符重载函数完成两个vector对象之间的赋值.

声明

c++11提供了多种简化声明的方式,尤其是在使用模板时

auto-变量类型推导

为什么需要类型推导

在定义变量时,必须先给出变量的实际类型,编译器才允许定义,但有些情况下可能不知道需要实际类型怎么给,或者类型写起来特别复杂

在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了,C++11中废弃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", "插入" } };
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();  //简化代码

	return 0;
}

自动类型推断在某些场景下还是非常必要的,因为编译器要求在定义变量时必须先给出变量的实际类型,而如果我们自己设定类型在某些情况下可能会出问题.比如:

int main()
{
	short a = 32670;
	short b = 32670;
	//c如果给成short,会造成数据丢失,如果能够让编译器根据a+b的结果推导c的实际类型,就不会存在问题
	short c = a + b;
	return 0;
}

decltype类型推导

关键字decltype将变量的类型声明为表达式指定的类型

为什么需要decltype

auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型

有时可能需要根据表达式运行完成之后结果的类型进行推导,因为编译期间代码不会运行,此时auto也就无法使用了


例子:

template<class T1, class T2>
T1 Add(const T1& left, const T2& right)	//返回值不一定是T1,可能是T2
{
    return left + right;
},

如果能用加完之后结果的实际类型作为函数的返回值类型就不会出错,但这需要程序运行完才能知道结果的实际类型,即RTTI(Run-Time Type Identification 运行时类型识别)


在C++98中已经支持RTTI:

  • typeid只能查看类型不能用其结果类定义类型
  • dynamic_cast只能应用于含有虚函数的继承体系中

运行时类型识别的缺陷是降低程序运行的效率


decltype是根据表达式的实际类型推演出定义变量时所用的类型

注意: 通过typeid(变量名).name()的方式可以获取一个变量的类型,但无法用获取到的这个类型去定义变量.

decltype除了能够推演表达式的类型,还能推演函数返回值的类型

1.推演表达式类型作为变量的定义类型

int main()
{
    int a = 10;
    double b = 20.0;
    decltype(a + b) c; //用decltype推演a+b的实际类型,作为定义c的类型
    cout << typeid(c).name() << endl;//检测c的类型 - double
}

2.推演函数返回值的类型

void* GetMemory(size_t size)
{
    return malloc(size);
}
int main()
{
    // 如果没有带参数,推导函数的类型
    cout << typeid(decltype(GetMemory)).name() << endl;//void * __cdecl(unsigned int)
    // 如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,并不会执行函数
    cout << typeid(decltype(GetMemory(0))).name() <<endl; //void*
    return 0;
}

decltype不仅可以指定定义出的变量类型,还可以指定函数的返回类型.比如:

template<class T1, class T2>
auto Add(T1 t1, T2 t2)->decltype(t1+t2) //指定函数的返回类型为t1+t2之后的类型
{
	decltype(t1+t2) ret;
	ret = t1 + t2;
	cout << typeid(ret).name() << endl;
	return ret;
}
int main()
{
	cout << Add(1, 2) << endl;;   //int
	cout << Add(1, 2.2) << endl;; //double
	return 0;
}

decltype的某些应用场景

int func(int a)
{
	cout << "int func(int a)" << endl;
	return a;
}
int main()
{
    int(*pfunc1)(int) = func; //pfunc1是函数指针
    //假设我们要定义一个和pfunc1相同类型的变量:
    //写法1:
	decltype(pfunc1) pfunc2 = func;
    //写法2:
	decltype(&func) pfunc3 = func;
    
    //decltype的一个使用场景1-要定义一个auto推导的对象的的拷贝
    map<string, string> dict = { { "sort", "排序" }, { "insert", "插入" } };
    auto it = dict.begin();
    decltype(it) copyIt = it;
    
    //场景2:decltype可以推导对象的类型,可以用来定义对象,也可以作为模板参数 
    vector<decltype(it)> v;
	v.push_back(it);
    return 0;
}

nullptr

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

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

在大部分情况下使用NULL不会存在什么问题,但是在某些极端场景下就可能会导致匹配错误.比如:

void f(int arg)
{
	cout << "void f(int arg)" << endl;
}
void f(int* arg)
{
	cout << "void f(int* arg)" << endl;
}
int main()
{
	f(NULL);    //void f(int arg)
	f(nullptr); //void f(int* arg)
	return 0;
}

NULL和nullptr的含义都是空指针,所以这里调用函数时肯定希望匹配到的都是参数类型为int*的重载函数,但最终却因为NULL本质是字面量0,而导致NULL匹配到了参数为int类型的重载函数,因此在C++中一般推荐使用nullptr.


范围for

只要容器支持了迭代器,我们可以使用范围for遍历容器

C++11中引入了基于范围的for循环,for循环后的括号由冒号分为两部分,第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围.比如

范围for的本质就是迭代器遍历,范围for会被编译器替换成迭代器

#include<map>
int main()
{
	//除了STL的容器可以支持范围for遍历,数组也可以
	//原生指针可以作为迭代器,比如vector,string的迭代器就是原生指针
	int a[] = { 1,2,3,4,5 };
	for (auto e : a)
	{
		cout << e << " ";
	}
	cout << endl;

	map<string, string> m{ {"sort","排序"},{"test","测试"},make_pair("hello","你好") };
	//当容器存的对象比较大/会发生深拷贝,比如string的赋值
	//最好给成&,此时kv就是m的每一个对象的别名,可以减少拷贝提高效率
	for (auto& kv : m)
	{
		//kv是pair对象
		cout << kv.first << " " << kv.second << endl;
	}
	cout << endl;
	return 0;
}

注意: 与普通循环类似,可用continue来结束本次循环,也可以用break来跳出整个循环.

范围for的使用条件

一、for循环迭代的范围必须是确定的

对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围.

二、迭代的对象要支持++和==操作

范围for本质上是由迭代器支持的,在代码编译的时候,编译器会自动将范围for替换为迭代器的形式.而由于在使用迭代器遍历时需要对对象进行++和==操作,因此使用范围for的对象也需要支持++和==操作.


STL的新变化

新容器:

C++11中新增了四个容器,分别是array、forward_list、unordered_map和unordered_set.但是实际最有用的是unordered_mapunordered_set

image-20220606113538379

一、array容器
array容器本质就是一个静态数组,即固定大小的数组.

array容器有两个模板参数,第一个模板参数代表的是存储的类型,第二个模板参数是一个非类型模板参数,代表的是数组中可存储元素的个数.比如:

int main()
{
	array<int, 10> a1;   //定义一个可存储10个int类型元素的array容器
	array<double, 5> a2; //定义一个可存储5个double类型元素的array容器
	return 0;
}

array容器与普通数组对比:

  • array容器与普通数组一样,支持通过[]访问指定下标的元素,也支持使用范围for遍历数组元素,并且创建后数组的大小也不可改变.
  • array容器与普通数组不同之处就是,array容器用一个类对数组进行了封装,并且在访问array容器中的元素时会进行越界检查.[]访问元素时采用断言检查,调用at成员函数访问元素时采用抛异常检查.
  • 而对于普通数组来说,一般只有对数组进行写操作时才会检查越界,如果只是越界进行读操作可能并不会报错
    • 原生数组对于越界的检查是抽查行为,有些越界是不检查的!

但array容器与其他容器不同的是,array容器的对象是创建在栈上的,因此array容器不适合定义太大的数组,array本质是鸡肋语法, 它的好处在于:支持迭代器,更好兼容STL容器玩法 ,对于越界的检查

二、forward_list容器
forward_list容器本质就是一个单链表,forward_list很少使用,原因如下:

  • forward_list只支持头插头删,不支持尾插尾删,因为单链表在进行尾插尾删时需要先找尾,时间复杂度为O(N).
  • forward_list提供的插入函数叫做insert_after,也就是在指定元素的后面插入一个元素,而不像其他容器是在指定元素的前面插入一个元素,因为单链表如果要在指定元素的前面插入元素,还要遍历链表找到该元素的前一个元素,时间复杂度为O(N).
  • forward_list提供的删除函数叫做erase_after,也就是删除指定元素后面的一个元素,因为单链表如果要删除指定元素,还需要还要遍历链表找到指定元素的前一个元素,时间复杂度为O(N).

因此一般情况下要用链表我们还是选择使用list容器(带头双向循环链表)


三、unordered_map和unordered_set容器
unordered_map和unordered_set容器底层采用的都是哈希表.

字符串转换函数

C++11提供了各种内置类型与string之间相互转换的函数,比如to_string、stoi、stol、stod等函数.

一、内置类型转换为string
将内置类型转换成string类型统一调用to_string函数,因为to_string函数为各种内置类型重载了对应的处理函数.

image-20221010172832638


二、string转换成内置类型
如果要将string类型转换成内置类型,则调用对应的转换函数即可.

image-20221010172846183


容器中的一些新方法

如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的

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

说明一下:emplace系列方法和新增的插入函数提高容器插入效率的原理,涉及C++11中的右值引用、移动语义和模板的可变参数等机制


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

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

相关文章

Java 输出机制 数据类型

目录 一、输出机制 1.print和println的差别 2.可接收不同类型参数 3.输出函数中 符号的使用 二、Java 数据类型 1.整型类型 2.浮点类型 3.字符类型 三、基本数据类型转换 1.自动类型转换 2.强制类型转换 3.练习题 四、基本数据类型和String类型的转换 1.基本类…

【LeetCode】 309.最佳买卖股票时机含冷冻期

309.最佳买卖股票时机含冷冻期&#xff08;中等&#xff09; 思路 状态定义 一、很容易想到四种状态&#xff1a; a.今天买入&#xff1b;b.今天卖出&#xff1b;c.昨天卖出&#xff0c;今天处于冷冻期&#xff0c;无法进行操作&#xff1b;d.今天不操作&#xff0c;处于持有…

SD卡变成RAW格式怎么办?SD卡RAW格式的解决办法

使用SD卡的小伙伴有没有遇到这种情况&#xff0c;SD卡无法访问提示格式化&#xff0c;查看SD卡的属性发现文件系统类型变成RAW格式&#xff0c;而非之前的NTFS或FAT32格式。那么当SD卡变成raw格式怎么办&#xff1f;如果里面有重要数据怎么办&#xff1f;SD卡RAW格式怎么恢复数…

【Java】什么是SOA架构?与微服务有什么关系?

文章目录 服务化架构微服务架构 我的一个微服务项目&#xff0c;有兴趣可以一起做 服务化架构 我们知道&#xff0c;早期的项目&#xff0c;我们都是把前后端的代码放在同一个项目中&#xff0c;然后直接打包运行这个项目&#xff0c;这种项目我们称之为单体项目&#xff0c;比…

m4a怎么转换成mp3的4种方法值得收藏

m4a怎么转换成mp3&#xff1f;首先我们得了解m4a是什么格式。m4a是MPEG-4音频标准的文件扩展名&#xff0c;它是一种音频格式&#xff0c;由苹果公司推出。该格式的音质没有损失&#xff0c;且不受版权保护&#xff0c;因此可以进行自由编辑和转发。该格式的兼容性相对较弱&…

PIE-SAR软件自动化编译与发布

1.背景 SVN版本控制下多人协调编写代码&#xff0c;会经常性的提交新功能&#xff0c;修改完善已有功能。产品经理、测试人员需定期回归测试&#xff0c;确保禅道Bug已经修复&#xff0c;这就需要经常性地打包软件。为了节省编译时间&#xff0c;也方便产品经理可随时去取最新…

MiniGPT-4,开源了!

上个月GPT-4发布时&#xff0c;我曾写过一篇文章分享过有关GPT-4的几个关键信息。 当时的分享就提到了GPT-4的一个重要特性&#xff0c;那就是多模态能力。 比如发布会上演示的&#xff0c;输入一幅图&#xff08;手套掉下去会怎么样&#xff1f;&#xff09;。 GPT-4可以理解…

基于51单片机的差分双路电压检测(基于ADC0832)

文章目录 前言一、本文任务二、材料三、电路图四、代码解读1.引脚定义及参数2.定时器中断与延时开启3.数码管显示定义及ADC0832函数初始化4.数据转换及数码管显示5.主函数及定时器函数6.所有代码&#xff08;就一个c文件&#xff09; 总结 前言 博主终于又空出时间啦&#xff…

二战失利,剩下的路?

作者&#xff1a;阿秀 校招八股文学习网站&#xff1a;https://interviewguide.cn 这是阿秀的第「260」篇原创 小伙伴们大家好&#xff0c;我是阿秀。 欢迎今年参加秋招的小伙伴加入阿秀的学习圈&#xff0c;目前已经超过 2300 小伙伴加入&#xff01;去年认真准备和走下来的基…

如何使用chatGPT生成小红书种草文案

如何使用chatGPT生成小红书种草文案 小红书拥有超千万的日活用户&#xff0c;为商家提供了广阔的变现空间和机会&#xff0c;成为商家选择在小红书上推广的原因之一。 小红书种草文案&#xff0c;例如具有影响力的热门话题、产品使用方法等内容可以让消费者迅速了解产品为品牌…

小米青春版路由器刷openwrt

下载小米路由器R1CL开发版 通过手动上传更新&#xff0c;更改固件版本 将之前地址栏URL中的 /web/home#router 替换为&#xff08;密码为admin&#xff09; /api/xqsystem/set_name_password?oldPwd123456789&newPwdadmin如果网页返回 {“code”:0} &#xff0c;则说明修…

JAVA的BIO、NIO、AIO模式精解(一)

1. BIO、NIO、AIO介绍 在不同系统或进程间数据交互&#xff0c;或高并发场景下都选哟网络通信。早期是基于性能低下的同步阻塞IO(BIO)实现。后支持非阻塞IO(NIO)。 前置须知&#xff1a;javsse&#xff0c;java多线程&#xff0c;javaIO&#xff0c;java网络模型 目的&#xf…

[江西专升本/信息技术]计算机网络基础

1、概论 目前主要从资源共享观点定义计算机网络&#xff1a; 用通信路线和通信设备将分布在不同地点的具有独立功能的多个计算机系统相互连接起来&#xff0c;在功能完善的网络软件的支持下实现彼此之间的数据通信和资源共享的系统&#xff1b; 我们可以这么说&#xff0c;“…

effective c++ item30-34

item30:理解inline 1、inline函数 用inline修饰函数可以防止multiple definition的错误 // foo.h inline int foo(int x){ // 如果不加inline&#xff0c;在编译时会有两个foo.h被包含进去&#xff0c;导致链接出错static int n 1;return x * (n ); } // bar1.cpp #includ…

【车道线算法】GANet-车道线检测环境配置一文通关

目录 GANet配置全纪录 下载代码 conda环境部署 安装torch和cudatoolkit 安装其他包 编译 总结 GANet配置全纪录 下载代码 GitHub - Wolfwjs/GANet: A Keypoint-based Global Association Network for Lane Detection. Accepted by CVPR 2022 进入代码网址的默认master…

ArcGIS Pro工程

目录 1 工程基础架构 2 工程内容 3 新建工程及工程文件 3.1 工程模板 3.2 工程名称和位置 3.2.1 基于“地图模板”创建新工程 3.2.2 基于“目录模板”创建新工程 3.2.3 基于“全局场景”创建新工程 3.2.4 基于“局部场景”创建新工程 3.3 工程文件 3.3.1 默认地理…

子元素选择器

知识点&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" c…

【MySQL高级】——用户与权限管理

一、用户管理 <1> 登录 mysql –h hostname|hostIP –P port –u username –p DatabaseName –e "SQL语句"-h参数 后面接主机名或者主机IP&#xff0c;hostname为主机&#xff0c;hostIP为主机IP。 -P参数 后面接MySQL服务的端口&#xff0c;通过该参数连接…

序列检测和序列发生器——verilog代码实现

文章目录 前言一、序列检测器1.1 重复序列检测1.1.1 序列缓存对比/移位寄存器法1.1.2 状态机法 1.2 非重复序列检测 二、序列发生器2.1 移位寄存器法2.2 反馈法2.3 计数器法 前言 2023.4.25 2023.4.26 学习打卡&#xff0c;天气转晴 一、序列检测器 1.1 重复序列检测 1.1.1 …

HTML基础标签

目录 1.html文件结构 2.注释 3.文本标签 4.图片 5.音频与视频 6.超链接 7.表单 8.列表&#xff08;可以嵌套&#xff09; 无序列表 有序列表 定义列表 9.表格 10.语义标签 11.特殊符号 1.html文件结构 <!-- 文档类型声明 --> <!DOCTYPE html> <html>…