了解c++11中的新增

news2024/11/19 21:30:28

一,统一的初始化列表

在引入c++11后,我们得出计划都可以用初始化列表进行初始化。

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

int  main()
{
	int i = 0;
	int j = { 0 };
	int k{ 0 };
	int l(0);
	//如日期类
	
	return 0;
}

//对象的初始化
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;
	}


//日期类对象的初始化
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, 1, 1); // old style
	// C++11支持的列表初始化,这里会调用构造函数初始化
	Date d2{ 2022, 1, 2 };
	Date d3 = { 2022, 1, 3 };
	//这里的本质就是,以该参数构造对象再拷贝给给这里的对象
	Date* d4 = new Date[3]{ {2023,5,3}, {2022, 1, 3},{2023,1,2} };
	return 0;
}

数组与链表的初始化

int main()
{
	vector<int> v = { 1,2,3,4,5,6 };
	list<string> l = { "hello","world" };
	return 0;
}

并且再c++11引入了std::initializer_list ,一种特殊的构造方式:

initiallizer_list

initializer_list是C++11提供的新类型,定义在头文件中。 用于表示某种特定类型的值的数组,和vector一样,initializer_list也是一种模板类型。即一组数据的类型。

一般它的作用也就是为了支持容器的参数列表的构造。

如下:通过typeid我们来查看il的类型,

库中的定义: 

 

 库中实现了三个成员函数,分别是首尾和大小。我们不难看出这肯定是实现了迭代器,也确实是这样样,他的迭代器就是他的原生指针。

int main()
{
	auto il = { 1,2,3,4,5 };
	cout << typeid(il).name()<<endl;
	auto it = il.begin();
	while (it != il.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
	for (auto it : il)
	{
		cout << it;
	}
	return 0;
}

 对于initailizer_list,不仅仅是一般的类型的数据的和,对于vector,list,map,set等构造都支持参数列表(nitailizer_list)这样的初始化:

int main()
{
	pair<string, string> kv = { "希尔排序","1" };
	map<string, string> p = { kv,{"冒泡排序","2"},{"快速排序","3"}};
	//初始化map时,除了用pair,我们这里也可以用initializer_list  ->实际上回隐式类型转换为pair
	for(auto &it:p)
	{
		cout << it.first<<" "<<it.second<< endl;
	}
	return 0;
}

 二,声明

auto

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

自动类型推导,更加简便的声明。实际当中,我们一般范围for用,

decltype

关键字 decltype 将变量的类型声明为表达式指定的类型。
int main()
{
	//对于类型推导 我们知道typid
	int i = 10;
	double j = 10.2;
	cout << typeid(i).name() << endl;
	cout << typeid(j).name() << endl;//获取类型的字符串 但不能当作类型去定义 
	//我们平时需要定义时就用auto定义,但若我们的模板参数需要这个类型如何取到这个类型
	//利用关键字decltype 获取数据类型
	vector<decltype(j)> v;
	v.push_back(1);
	v.push_back(2);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i]<<" ";
	}
	decltype(j) data;//可以当作类型用定义
	return 0;

}

三,范围for

就是迭代器基础实现的遍历,写起来更加方便,我们差不多已经都熟练使用。

四,智能指针

智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。

五,c++11种STL库中的变化

  新容器:forward_list(单链表),arry(静态数组),两个哈希表封装的无序关联容器unordered_map,unordered_set。

实际应用中,arry没谁用,我们有vetor,单链表意义也不大,虽然节省空间,但对于尾删效率太低下了,较有大用处的是者两个无序容器.

六,右值引用与移动语义(重要)

什么是左值,什么是右值?

传统的 C++ 语法中就有引用的语法,而 C++11 中新增了的右值引用语法特性。
我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名
什么是左值?左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针) 我们可以获取它的地址 + 可以对它赋
值, 左值可以出现赋值符号的左边,右值不能出现在赋值符号左边 。定义时 const 修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
int main()
{
	//下面三个变量都是左值     我们可以给它赋值,主要看他是否可以取地址
	int* p = new int(1);
	int b = 0;
	const int c = 10;
	//i还是左值
	int i = 0;
	int j = i;

}

什么是右值?右值引用?
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值 ( 这个不能是左值引
用返回 ) 等等, 右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边, 右值不能
取地址 。右值引用就是对右值的引用,给右值取别名。
int main()
{
	int i = 0, j = 0;
	//如下都是右值  右值可以是表达式,返回值,右值无法取地址
	10;
	i + j;
	fmin(i , j);

	//之前的引用都是左值引用,我们来看看右值引用
	int&& r = 10;
	double &&r1= i + j;
	int&& min = fmin(i, j);

}

左值引用不能直接给给右值取别名,需要const。右值引用也不能直接给左值引用,这里可以move后引用。

int main()
{
	//左值引用给右值取别名,不能直接引用,右值不能被修改,因此需要const
	const int& i = 10;

	int&& j = 10;//右值引用右值
	int&& m = i + j;
	//右值引用引用左值     不能直接引用,还是需要转化类型   
	//右值引用可以给move后的左值引用
	int p = 10; int q = 10;
	int&& r = move(q);
	int&& n = (const int) q;

}

引入右值引用与左值引用的效果一样,减少大量拷贝。

那么右值引用是如何使用的?

右值引用的场景

因为在函数的返回值中,如果要对函数返回的值引用,则必须要满足,在函数的声明周期结束后,值的生命周期还在,否则就无法使用引用。

那我们想要返回该如何?比如说我们自己实现string里面的tostring:
//那么如何实现这里的ret返回引用呢?
string tostring(int x)
{
	string ret;
	while (x)
	{
		int val = x % 10;
		x = x / 10;
		ret += (val + '0');
	}
    reverse(ret.begin(),ret.end());
	return ret;
}

在正常引用函数的返回值肯定不行。

首先函数返回值是一个右值,我们需要使用右值引用,其次右值引用还是要考虑到该问题,函数调用完毕,释放函数栈帧时,对应的返回值的生命周期也结束了,此时引用,引用的就是个空。
首先在c++中,右值分为纯右值与将亡值(自定义的右值)。
首先对于正常的返回,不调用引用,过程是这样的:

首先ret在这里会调用三次深拷贝,代价太大,那么有无优化的方案?

 对于这里的ret,还是传值返回,但是在即将销毁时,我们可以将它识别是一个将亡值(右值),对于将亡值,我们拷贝构造时,使用右值引用传参(移动拷贝),直接把资源转移过来,不再进行深度拷贝,但是在进入main函数中的拷贝之后,赋值是不支持右值对象的,因此这里还需要实现右值赋值。

amespace myspace
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		string tostring(int x)
		{
			string ret;
			while (x)
			{
				int val = x % 10;
				x = x / 10;
				ret += (val + '0');
			}
			return ret;
		}
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		// 拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;
			string tmp(s._str);
			swap(tmp);
		}
		// 赋值重载
		string& operator=(const string& s)
		{
				cout << "string& operator=(string s) -- 深拷贝" << endl;
			string tmp(s);
			swap(tmp);
			return *this;
		}
		// 移动构造  右值引用
		string(string&& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(string&& s) -- 移动语义" << endl;
			swap(s);
		}
		// 移动赋值  右值引用
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动语义" << endl;
			swap(s);
			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}
				_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		const char* c_str() const
		{
			return _str;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};
}

通过右值引用我们减掉了深度拷贝的代价。这里我们一般还可以通过调试查看函数调用信息,

对于将亡值,我们一般使用move将一个左值转化为将亡值。自定义的右值一般也是将亡值。

仔细看的话,用过右值引用,我们还将他的生命周期延长了,我们通过右值引用使得这份资源还在。

当然我这里的右值引用,移动构造对于深拷贝就能发挥它的作用,浅拷贝的自定义类型没什么用。

注意:注意move移动语义,本是是不会改变这个值的属性,而是调用后的返回值的类型发生了改变。

其次对于一个右值的引用之后它的属性是一个左值,因为右值不能被修改,但是右值的右值引用可以被修改,否则无法实现移动构造,与移动复制。

库中的一些应用

 除了返回值可以被引用外,移动构造与移动拷贝相对于左值的拷贝构造,赋值。更加的快速和节省空间,因为我们这里直接是引用。

通过右值引用实现了返回值的引用,以这种方式许多场景下的应用就可以实现了。

c+11后,我们通过转化为右值,使用移动构造,移动拷贝,效率就会高许多。

STL容器在c++11后,都增加了移动构造与移动赋值。

vector的构造与赋值

 

list的构造与赋值

以及push操作也基本添加了右值版本:

万能引用

c++11在提供右值及右值引用后,还增加了万能引用。

所谓的万能引用,就是模板参数的引用,这里用的是&&,但不代表是右值引用。

格式如下:

template<typename T>
void PerfectForward(T&& t)
{
 Fun(t);
}

通过万能引用,是左值就调左值引用,是右值就调右值引用。但是还是要记住一点,右值被右值引用之后,属性是左值,因此在处理右值传参用右值对应的接口,我们都需要吧接口里的值的类型在move一下。

注意事项:

针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:
如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类
型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
如果实现了就调用移动构造,没有实现就调用拷贝构造。
如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋
值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。 ( 默认移动赋值跟上面移动构造
完全类似 )
如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

七.defalut与delete

强制生成默认函数的关键字default,;取消生成默认函数的关键字delete:
C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原
因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以
使用default关键字显示指定移动构造生成。 当然我们也可以取消不让这些函数生成。

八,模板的可变参数

首先我们知道函数的参数可以是可变参数,c++11对模板也引入了可变参数。

这里的参数,我们叫可变参数包,

template<class ...Args> //模板的可变参数包
void show(Args...arg)
{
	//可以包含任意多个类型的参数
}
STL容器中的 empalce相关接口函数:就是可变参数
emplace 系列的接口,支持模板的可变参数,并且也可以万能引用。
以vector为例,在c++11当中增加了两个家口,emplace与emplace_back,这两个接口都是用来
插入的,emplace_back尾插,那么这两个插入与insert有什么区别呢?
首先就是可变参数,emplace会根据参数将Args作为构造函数的参数构造出一个该元素,然后插入其中。
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector = {10,20,30};

  myvector.emplace_back (100);
  myvector.emplace_back (200);

  std::cout << "myvector contains:";
  for (auto& x: myvector)
    std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

//运行结果  myvector contains: 10 20 30 100 200

在引入移动构造与构造时,insert就是先构造,在移动构造插入,而对于emplace是直接构造插入。对于大一点的浅拷贝的自定义类型,emplace相对于会更好一点。

九,lambda表达式

在c++98之前,比如我们在用sort进行排序时,我们是传一个仿函数,且该种排序只能支持库里提供的类型,另外的类型就需要我们重写一个仿函数传进去。

操了c++11,虽然问题得到了解决,但是人们认为这样写还是太过麻烦,比如每次传参进去的仿函数都必须以它如何排序的方式进行命名,因为具体实现的比较我们是看不到的,因此借鉴了python的lambda表达式,实现更加方便,更加清晰的比较。

lambda表达式的构成:

lambda 表达式书写格式: [capture-list] (parameters) mutable -> return-type { statement
}
lambda 表达式各部分说明:
[capture-list] : 捕捉列表 ,该列表总是出现在 lambda 函数的开始位置, 编译器根据 []
判断接下来的代码是否为 lambda 函数 捕捉列表能够捕捉上下文中的变量供 lambda
函数使用
(parameters) :参数列表。与 普通函数的参数列表一致 ,如果不需要参数传递,则可以
连同 () 一起省略。
mutable :默认情况下, lambda 函数总是一个 const 函数, mutable 可以取消其常量
性。使用该修饰符时,参数列表不可省略 ( 即使参数为空 ) 。---不需要一般可以忽略不写
->returntype :返回值类型 。用 追踪返回类型形式声明函数的返回值类型 ,没有返回
值时此部分可省略。 返回值类型明确情况下,也可省略,由编译器对返回类型进行推
{statement} :函数体 。在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。

事实上lalmbda本质就是一个函数对象,我们一般这样去使用它:

int main()
{
	//比如简单写一个打印出入的参数
auto it=	[]       (int x)    ->int   { cout << x; return 0; };
           //捕捉列表  参数列表  返回类型   函数体
 //我们一般用auto自定推导类型来获取这个对象
   it(1);//对象传参
//当然我们也可以省略返回值类型,它可以自动推导
//auto it=[](int x){ cout << x; return 0; };

   return 0;
}

 那么我们就可以用lambda去替换仿函数。

现在我们就可以用lambda表达式去实现仿函数一样的功能:

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
	//仿函数
	sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), ComparePriceGreater());
	//lambda
	//这里的lambda可以理解为匿名函数对象
	sort(v.begin(), v.end(), [](Goods &it1,  Goods& it2) {return it1._price > it2._price; });
	sort(v.begin(), v.end(), [](Goods &it1, Goods& it2) {return it1._price < it2._price; });

	return 0;
}

因为sort函数提供的是模板(对于比较这一部分),因此我们只要传参可调用的对象就可以。

那么有人就开始疑惑了,lambda返回类型到底是一个什么?通过typeid我们可以看看:

int main()
{
	auto p=[](Goods& it1, Goods& it2) {return it1._price > it2._price; };
	auto q = [](Goods& it1, Goods& it2) {return it1._price > it2._price; };
	cout << typeid(p).name()<<endl;
	cout << typeid(q).name()<<endl;
}

 实际上是一个类,每个lambda都有自己对应的类。

关于捕捉列表,lambda表的是其他构成我们能理解,但对于捕捉列表是什么呢?

所谓的捕捉,就是可以将父作用域里的变量直接拿来使用,但传值过来的变量无法被修改。

除了传值,也可以传引用捕捉,但在书写方面与取地址写法一样,注意别混淆。

传值就是普通函数传参,传引就是引用传参。如果想捕捉地址,就实现把地址取出来。

当然捕捉引用时,它自动传参时,此时就不再使用mutable了。

即:

int x = 1; int y = 2;
	//不捕获时
		auto q = [](int x, int y)->void
	    {
		int temp = x;
		x = y;
		y = temp;
	    };
		q(x, y);
		//这里只是作为参数传递过去,形参的改变不影响实参
		cout<<x<<" " << y << endl;
		//捕获时,但注意,这里虽然捕获了,可以直接用
		//但此时默认情况下这里的函数是不能修改的,需要加入mutable表示可修改
		auto p = [x, y]()mutable-> void 
	    {
		int temp = x;
		x = y;
		y = temp;
	    };
		p();
		//这里只是作为参数传递过去,形参的改变不影响实参
		cout << x << " " << y << endl;
		auto n = [&x, &y]()-> void
		{
			int temp = x;
			x = y;
			y = temp;
		};
		n();
		//这里是传引用,因此会完成交换
		cout << x << " " << y << endl;

lambda的原理也是仿函数。

十,包装器

function

有了仿函数,lambda,实际上还有函数指针,这三个本质其实都一样,都是一个函数,可以被其他对象调用去实现某个功能。因为除了函数指针和仿函数还能传,lanmbda的类型我们是不得而知的,需要function去将这些包装,我们能直接获取其类型。

因此在c++11中又提出一个概念包装器,就是跟适配器一样。

我们之前学习单链表,栈和队列等就是用vector,list去适配出这样的一个结构。

而这里的包装器,就是用函数指针,或者lambda,仿函数去适配(包装)我们所需要的一个“函数对象”,去被调用。

语法:class function

std::function 在头文件 < functional >
// 类模板原型如下
template < class T > function ;     
template < class Ret , class ... Args >
class function < Ret ( Args ...) > ;
模板参数说明:
Ret : 被调用函数的返回类型
Args… :被调用函数的形参

 function的本质就是一个类模板,适配就是去适配 仿函数,函数指针,lambda的其中一个。

//包装器 function
//我们还是以交换两个整数为例
//仿函数
struct Swap1
{
	void operator()(int& x, int& y)
	{
		int temp = x;
		x = y;
		y = temp;
	}
};
//函数
void Swap2(int& x,int& y)
{
	int temp = x;
	x = y;
	y = temp;
}
//lambda
auto Swap3 = [](int& x, int& y)->void {int temp = x; x = y; y = temp; };
//首先我们先来使用一下
int main()
{
	int x = 1; int y = 2;
	//可以包装这三个
	function<void(int&, int&)> p1 = Swap1();
	p1(x, y);
	cout << x << " " << y << endl;
	function<void(int&, int&)> p2 = Swap2;
	p2(x, y);
	cout << x << " " << y << endl;
	function<void(int&, int&)> p3 = Swap3;
	p3(x, y);
	cout << x << " " << y << endl;
	//通过function模板 ,在传入参数时,我们就可以选择三个其中之一进行传参
	map<string, function<void(int&, int&)> >  op = { {"仿函数", Swap1()},{"函数指针", Swap2},{"lambda", Swap3} };
	/*m.insert(make_pair("仿函数", Swap1()));
	m.insert(make_pair("函数指针", Swap2));
	m.insert(make_pair("仿函数", Swap3));*/
	//map<string, function<void(int&, int&)> >  m = { {"仿函数", p1},{"函数指针", p2},{"仿函数", p3} };
	op["仿函数"](x, y); 
	op["函数指针"](x, y);
	op["lambda"](x, y);

}

当然这里我们的函数的参数类型是一样的。

包装成员函数

在包装成员函数时,我们需要注意几点:

1.指定类域

2.要在成员函数前加&符号,才表示成员函数的地址

3.传参需要加入他的地址

class Func
{
public:
	static int Add1(int x, int y)
	{
		return x + y;
	}
	double Add2(double  x, double  y)
	{
		return x + y;
	}
};
int main()
{
	//如果是static,我们可以直接包装
	function<int(int, int)> p1 = Func::Add1;
	cout << p1(1, 2)<<endl;
	//如果是普通成员函数,则还需要一个对象指针
	Func a;
	function<double(Func*, double, double)> p2 = &Func::Add2;
	cout << p2(&a, 1.1, 2.1) << endl;
	//对象也可以
	function<double(Func a, double, double)> p3 = &Func::Add2;
	Func b;
	cout << p3(b,1.2, 2.3) << endl;
}

bind

除了function,还有第二个包装器bind:

std::bind 函数定义在头文件中, 是一个函数模板,它就像一个函数包装器 ( 适配器 ) 接受一个可
调用对象( callable object ),生成一个新的可调用对象来 适应 原对象的参数列表 。一般而
言,我们用它可以把一个原本接收 N 个参数的函数 fn 通过绑定一些参数,返回一个接收M个(M
可以大于N,但这么做没什么意义)参数的新函数 。同时,使用 std::bind 函数还可以实现参数顺
序调整等操作。
// 原型如下:
template < class Fn , class ... Args >
/* unspecified */ bind ( Fn && fn , Args && ... args );
// with return type (2)
template < class Ret , class Fn , class ... Args >
/* unspecified */ bind ( Fn && fn , Args && ... args )

 可以用来调整参数的位置,

int main()
{
 //表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定
 std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1, placeholders::_2);
 
 //表示绑定函数 plus 的第一,二为: 1, 2
 auto  func2 = std::bind(Plus, 1, 2);   
 cout << func1(1, 2) << endl;
 cout << func2() << endl;
}

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

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

相关文章

JS基础之原型原型链

JS基础之原型&原型链 原型&原型链构造函数创建对象prototypeprotoconstructor实例与原型原型的原型原型链其他constructorproto继承 原型&原型链 构造函数创建对象 我们先使用构造函数创建一个对象&#xff1a; function Person(){ } var person new Person();…

【数据结构和算法】到达首都的最少油耗

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 三、代码 四、复杂度分析 前言 这是力扣的2477题&#xff0c;难度为中等&#xff0c;解题方案有很多种&…

tomcat源码学习记录

tomcat 学习记录 tomcat 编译ant 下载编译运行 源码Debug运行 Bootstrap运行Tomcat查看状态 pom.xml测试EmbeddedTomcat 参考书籍博客 tomcat 编译 下载 tomcat 10 源码&#xff0c;解压然后idea导入 包存放的默认位置如下&#xff1a;base.path${user.home}/tomcat-build-lib…

Linux升级nginx版本

处于漏洞修复目的服务器所用nginx是1.16.0版本扫出来存在安全隐患&#xff0c;需要我们升级到1.17.7以上。 一般nginx默认在 /usr/local/ 目录&#xff0c;这里我的nginx是自定义的路径安装在 /app/weblogic/nginx 。 1.查看生产环境nginx版本 cd /app/weblogic/nginx/sbin/…

class065 A星、Floyd、Bellman-Ford与SPFA【算法】

class065 A星、Floyd、Bellman-Ford与SPFA【算法】 2023-12-9 19:27:02 算法讲解065【必备】A星、Floyd、Bellman-Ford与SPFA code1 A*算法模版 // A*算法模版&#xff08;对数器验证&#xff09; package class065;import java.util.PriorityQueue;// A*算法模版&#xff…

Elon Musk艾隆・马斯克的聊天机器人Grok上线可以使用啦,为X Premium Plus订阅者推出

艾隆・马斯克旗下的 AI 初创公司X&#xff08;前身“推特”&#xff09;开发的 ChatGPT 竞争对手 Grok 已经在 X 平台上正式推出。Grok 是一个基于生成模型 Grok-1的聊天机器人&#xff0c;它能够回答问题并提供最新的信息。与其他聊天机器人不同&#xff0c;Grok 可以实时获取…

luceda ipkiss教程 44:在PyCharm 中设置Template text

通过设置Template text&#xff0c;可以提升写代码的速度和版图设计效率。 设置了Template text&#xff0c;在PyCharm 命令窗口输入i3后按enter建&#xff0c;就可以快速输入 from ipkiss3 import all as i3 这一段代码&#xff0c;使用起来也是非常方便&#xff1a; 设置过程…

万界星空科技mes系统中看板管理

我们很多企业现在都有大屏&#xff0c;那到底万界星空科技低代码云mes系统管理中看板管理有什么作用&#xff1f;我总结了几条: 1.提高车间的生产效率 2.有效的监控设备运行状况 3.控制生产线运行 4.增加和改善用户体验 5.提高工作效率和工作安全性

课堂练习3.4:进程的切换

3-9 课堂练习3.4:进程的切换 进程切换是支持多进程的一个关键环节,涉及到 CPU 现场的保存和恢复,本实训分析 Linux 0.11 的进程切换过程。 第1关第一次进程切换过程分析 任务描述 本关任务回答问题: 在第一次进程切换时: 1.是从几号进程切换到几号进程?0 号进程和 1 号…

人工智能大型语言模型的突破

近年来&#xff0c;随着深度学习和人工智能技术的飞速发展&#xff0c;大型语言模型在自然语言处理领域取得了巨大的突破&#xff0c;引发了广泛的关注和讨论。本文将介绍大型语言模型的发展历程、技术原理、应用场景以及未来发展趋势。 一、发展历程大型语言模型的发展可以追…

Android : Xui- RecyclerView+BannerLayout 轮播图简单应用

实例图&#xff1a; 1.引用XUI http://t.csdnimg.cn/Wb4KR 2.创建显示图片布局 banner_item.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"…

综述 2017-Genome Biology:Alignment-free sequence comparison

Zielezinski, Andrzej, et al. "Alignment-free sequence comparison: benefits, applications, and tools." Genome biology 18 (2017): 1-17. https://genomebiology.biomedcentral.com/articles/10.1186/s13059-017-1319-7 被引次数&#xff1a;476应用问题&…

【九】spring、springmvc、springboot、springcloud

spring、springmvc 、springboot 、springcloud 简介 从事IT这么些年&#xff0c;经历了行业技术的更迭&#xff0c;各行各业都会有事务更新&#xff0c;IT行业技术更迭速度快的特点尤为突出&#xff0c;或许这也是从事这个行业的压力所在&#xff0c;但另一方面反应了这个行业…

利用jdbc对数据库进行增删改查

步骤/过程&#xff1a; 1&#xff0c;导入驱动包 2&#xff0c;加载驱动包 3&#xff0c;输入信息&#xff0c;进行数据库连接 4&#xff0c;创建 statement对象 5&#xff0c;执行sql语句 6&#xff0c;如果是查询操作&#xff0c;利用ResultSet处理数据&#xf…

【动手学深度学习】(十一)池化层+LeNet

文章目录 一、池化层1.理论知识2.代码 二、LeNet1.理论知识2.代码实现 【相关总结】nn.MaxPool2d() 卷积层对位置比较敏感 一、池化层 1.理论知识 二维最大池化 填充、步幅和多个通道 池化层与卷积层类似&#xff0c;都具有填充和步幅没有可学习的参数在每个输入通道应用池…

【出现模块node_modules里面包找不到】

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 一、出现的问题二、解决办法三、其它可供参考 一、出现的问题 在本地运行 npm run docs:dev之后&#xff0c;出现 Error [ERR_MODULE_NOT_FOUND]: Cannot find package Z:\Blog\docs\node_modules\htmlparser2\ imported from Z:\Blo…

CCF计算机软件能力认证202309-1坐标变换(其一)(C语言)

ccf-csp计算机软件能力认证202309-1坐标变换&#xff08;其一&#xff09;(C语言版) 题目内容&#xff1a; 问题描述 输入格式 输出格式 样例输入 3 2 10 10 0 0 10 -20 1 -1 0 0样例输出 21 -11 20 -10样例解释 评测用例规模与约定 解题思路 1.第一步分析问题&…

Redux Toolkit(RTK)在React tsx中的使用

一个需求: header组建中有一个搜索框,然后这个搜索框在其他页面路由上都可以使用:例如这两个图共用顶部的搜索框; 我之前的做法就是组建传值, 在他们header 组建和 PageA ,B 的父级组件上定一个值,然后顶部变化传到父级组件,在从父级组件传到page组件,有点繁琐,现在说一下利用…

Javaweb之 依赖管理的详细解析

04. 依赖管理 4.1 依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖&#xff1a; 例如&#xff1a;在当前工程中&#xff0c;我们需要用到logback来记录日志&#xff0c;此时就可以在maven工程的pom.xml文件中&#xff0c;引入logback的依…

16.Java程序设计-基于SSM框架的android餐厅在线点单系统App设计与实现

摘要&#xff1a; 本研究旨在设计并实现一款基于SSM框架的Android餐厅在线点单系统&#xff0c;致力于提升餐厅点餐流程的效率和用户体验。通过整合Android移动应用和SSM框架的优势&#xff0c;该系统涵盖了用户管理、菜单浏览与点单、订单管理、支付与结算等多个功能模块&…