【C++】C++11【上】列表初始化|声明|新容器|右值引用|完美转发|新的类功能

news2024/11/15 19:33:31

目录

1、 C++11简介

2、 统一的列表初始化

2.1 {}初始化

2.2 std::initializer_list

 3、声明

 3.1 auto和范围for

3.1decltype

3.3 nullptr

 4、新容器

5、 右值引用

5.1左值引用和右值引用

5.2 左值引用与右值引用比较 

5.3 左值和右值引用使用场景及意义

 6、完美转发

7、新的类功能

7.1默认成员函数

7.2强制生成默认函数的关键字default:

7.2禁止生成默认函数的关键字delete:


 C++11特性我分为【上】【下】两部分来写,本文介绍【上】

1、 C++11简介

C++0x C++11 C++ 标准 10 年磨一剑,第二个真正意义上的标准珊珊来迟。相比于 C++98/03 C++11 则带来了数量可观的变化,其中包含了约 140 个新特性,以及对 C++03 标准中 600 个缺陷的修正,这使得 C++11 更像是从 C++98/03 中孕育出的一种新语言。相比较而言, C++11 能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更 强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个 重点去学习 C++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

2、 统一的列表初始化

2.1 {}初始化

C++98 中,标准允许使用花括号 {} 对数组或者结构体元素进行统一的列表初始值设定。比如:
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;
}
C++11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围,使其可用于所有的内置类型和用户自
定义的类型, 使用初始化列表时,可添加等号 (=) ,也可不添加
class Point
{
public:
	Point(int x = 0, int y = 0) : _x(x), _y(y)
	{}

private:
	int _x;
	int _y;
};

int main()
{
	int x = 1;
	int y{ 2 };//c++11,没必要学,没意义

	//C++11才支持的花括号列表初始化(容器都可以用{}初始化,数组也适用)

    int array1[]{ 1, 2, 3, 4, 5 };
    int array2[5]{ 0 };
	
    vector<int> v1{ 1,2,3,4,5 };
	vector<int> v2 = { 1,2,3,4,5 };

	list<int> l1{ 1,2,3,4,5 };
	list<int> l2 = { 1,2,3,4,5 };

	map<string, int> m{ {"苹果", 1},{"西瓜",3},{"香蕉",2}};//map的每个对象都是pair
	map<string, int> m1 = { {"苹果", 1},{"西瓜",3},{"香蕉",2} };

	//对于类的构造函数的初始化
	Point p1(1, 2); //正常情况下支持的
	Point p2{ 1, 2 };
	Point p3 = { 1, 2 };

	//c++11中的列表初始化也可用于new表达式
	int* pa = new int[4] {0};
    
    return 0;
}

2.2 std::initializer_list

①、类型(其为一个类模板) 

template<class T> class initializer_list;

②、使用场景

std::initializer_list可以认为是一个容器,其 一般作为构造函数的参数,C++11 STL中的不少容器就增加std::initializer_list 作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值。
//initializer_list的使用(两种写法)
auto i1 = { 10, 20, 30 }; //the type of i1 is an initializer_list
initializer_list<int> i2 = { 1, 2, 3 };

//容器是如何支持这种花括号的列表初始化的呢?
//使模拟实现的vector也支持{}初始化和赋值
/*vector(initializer_list<T>l)
	:_capacity(l.size()), _size(0)
{	//为了讲解,这里假设vector没用指针实现,而是用_capacity,_size实现
	_array = new T[_capacity];
	for (auto e : l)
		_array[_size++] = e;
}*/
//其他容器也类似

注:容器支持花括号列表初始化,本质是增加了一个initializer_list的构造函数,initializer_list可以接收{}列表  


 3、声明

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

 3.1 auto和范围for

C++98 auto 是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以 auto 就没什么价值了。 C++11 中废弃 auto 原来的用法,将
其用于实现自动类型推断。这样要求必须进行显式初始化,让编译器将定义对象的类型设置为初
始化值的类型。
//auto和范围for(熟悉)->简化了代码的写法

//auto不能做形参和返回值
//auto func(auto e)
//{}
int main()
{
	std::map<std::string, std::string> dict = { {"leverage","影响力"}, {"acre", "英亩"} };
	std::map<std::string, std::string>::iterator it1 = dict.begin();
	auto it2 = dict.begin();//用auto明显更方便书写了

	//注:这里当容器存的对象比较大时或这个对象要做深拷贝,如string
	//最好给引用和const,可以减少拷贝,提高效率
	for (const auto& e : dict) 
	{//容器支持范围for原理:范围for会被编译器替换成迭代器,则支持迭代器就支持范围for
		cout << e.first << e.second << endl;//acre英亩\nleverage影响力
    }

	//注:auto生成的迭代器是可以当参数进行传参的
	//因为auto生成对象跟只用类型对象是一样的,即it1与it2是一样的,没有区别   
	//唯一区别:it2类型是编译器自动推导出来的
	//auto的优势就是可以把类型比较复杂的地方,简化代码的写法

	//除了STL的容器可以用范围for用法,数组也可以(原生指针也可以认为是天然迭代器,如vector
	//string等迭代器就是原生指针
	int a[] = { 1,2,3,4,5,6 };
	for (auto e : a)
	{
		cout << e << " ";
	}
	cout << endl;
}

3.1decltype

关键字 decltype 将变量的类型声明为表达式指定的类型
//类型推导,属于RTTI (run time type identification)【了解】
//程序运行时对象的类型识别
int main()
{
	int a = 10;
	int b = 20;
	double c = 10;

	auto d = a + b;
	auto e = a + c;

	//拿到类型名称的字符串
	cout << typeid(d).name() << endl; //int
	cout << typeid(e).name() << endl; //double
	string s;
	cout << typeid(s).name() << endl; //class std::basic_string<char,....>

	//若想定义一个跟d一样类型的对象
	//typeid(d).name() f;   //报错,故用decltype
	
	//通过对象去推类型
	decltype(e) g;
	decltype(e) h;

	cout << typeid(g).name() << endl; //double
	cout << typeid(h).name() << endl; //double

	return 0;
}

3.3 nullptr


 4、新容器

容器中的一些新方法
如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的。 比如提供了 cbegin cend 方法返回 const 迭代器等等,但是实际意义不大,因为 begin end也是可以返回 const 迭代器的,这些都是属于锦上添花的操作。
实际上 C++11 更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本。
但是这些接口到底意义在哪?网上都说他们能提高效率,他们是如何提高效率的?
请看下面的右值引用和移动语义的讲解。另外 emplace还涉及模板的可变参数,也需要再继续深入学习后面的知识。

5、 右值引用

5.1左值引用和右值引用

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以我们之前学习的引用就叫左值引用。无论左值引用还是右值引用,都是给对象取别名。不过左值引用主要给左值取别名,右值引用主要给右值取别名

什么是左值?什么是左值引用?
左值是一个表示数据的表达式 ( 如变量名或解引用的指针 ) 我们可以获取它的地址 + 可以对它赋
值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边 。定义时 const 修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
// 以下的p、b、c、*p都是左值
int* p = new int(0);
int b = 1;
const int c = 2;
// 以下几个是对上面左值的左值引用int*&rp=p;
int& rb = b;
const int& rc = c;
int& pvalue = *p;

什么是右值?什么是右值引用?

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。

// 以下几个都是常见的右值
10;
x + y;
fmin(x, y);

// 以下几个都是对右值的右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);

// 这里编译会报错:error C2106: “=”: 左操作数必须为左值
10=1;
x + y = 1;
fmin(x, y) = 1;
需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可
以取到该位置的地址,也就是说例如:不能取字面量 10 的地址,但是 rr1 引用后,可以对 rr1 取地
址,也可以修改 rr1 。如果不想 rr1 被修改,可以用 const int&& rr1 去引用,是不是感觉很神奇,
这个了解一下实际中右值引用的使用场景并不在于此,这个特性也不重要。
double x = 1.1, y = 2.2;
int&& rr1 = 10;
const double&& rr2 = x+y;
rr1 = 20;
rr2 = 5.5;  // 报错

5.2 左值引用与右值引用比较 

 左值引用总结:

1. 左值引用只能引用左值,不能引用右值。
2. 但是 const 左值引用既可引用左值,也可引用右值。(这也说明了我们建议加const的原因之一)
//左值引用不能直接引用右值,const左值引用既可以引用左值,也可引用右值
//int& e = 10;
//int& f = x + y;
const int& e = 10;
const int& f = x + y;
右值引用总结:
1. 右值引用只能右值,不能引用左值。
2. 但是右值引用可以 move 以后的左值。
按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?因为:有些场景下,可能 真的需要用右值去引用左值实现移动语义。 当需要用右值引用引用一个左值时,可以通过 move 函数将左值转化为右值 C++11 中, std::move() 函数位于 头文件中,该函数名字具有迷惑性,它 并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义
//右值引用只能引用右值,不能引用左值,但可以引用move后的左值
//error C2440: “初始化”: 无法从“int”转换为“int &&”
//message : 无法将左值绑定到右值引用
//int&& mm = a;
int&& mm = move(a);

5.3 左值和右值引用使用场景及意义

前面我们可以看到左值引用既可以引用左值和又可以引用右值(加const才行),那为什么 C++11还要提出右值引用呢?下面我们来看看左值引用的短板,右值引用是如何补齐这个短板的。
左值引用的使用场景:
做参数和做返回值都可以提高效率。
void func1(string s)
{}
void func2(const string& s)
{}
int main()
{
 string s1("hello world");
 // func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值
 func1(s1);
 func2(s1);
 // string operator+=(char ch) 传值返回存在深拷贝
 // string& operator+=(char ch) 传左值引用没有拷贝提高了效率
 s1 += '!';
 return 0;
}
左值引用的短板:
但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如: string to_string(int value)函数中可以看到,这里只能使用传值返回,传值返回会导致至少 1 次拷贝构造 ( 如果是一些旧一点的编译器可能是两次拷贝构造 )
这里用string中的to_string来说明这个问题:
namespace mz
{
	string to_string(int value)
	{
		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}
		string str;
		while (value > 0)
		{
			int x = value % 10;
			value /= 10;
			str += ('0' + x);
		}
		if (flag == false)
		{
			str += '-';
		}
		std::reverse(str.begin(), str.end());
		return str;
	}
}
int main()
{
	// 在mz::string to_string(int value)函数中可以看到,这里只能使用传值返回,
	// 传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。
	string ret1 = mz::to_string(1234);
	string ret2 = mz::to_string(-1234);
	cout << ret1 << endl; //1234
	cout << ret2 << endl; //-1234

	return 0;
}


右值引用的使用场景:

场景1(简单应用)

template<class T>
void f(T& a)
{
	cout << "void f(const T& a)" << endl;
}

template<class T>
void f(T&& a)
{
	cout << "void f(const T&& a)" << endl;
}

int main()
{
	int x = 10;
	//f的左值右值引用的参数不同,故构成函数重载
	f(x);  //void f(const T& a)  ->匹配左值引用
	f(10); //void f(const T&& a) ->匹配右值引用

	return 0;
}

场景2

C++11又将右值区分为:纯右值和将亡值
纯右值:基本类型的常量或者临时对象
将亡值:自定义类型的临时对象

以我们模拟实现的String为例,看看右值引用的应用场景 

class String
{
public:
	String(const char* str = " ")
	{
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	//s2(s1)
	String(const String& s)
	{
		cout <<"String(const String& s)-拷贝构造-效率低" << endl;
		_str = new char[strlen(s._str) + 1];
		strcpy(_str, s._str);
	}

	//s3(右值-将亡值)
	String(String&& s)
		:_str(nullptr)
	{
		//传进来的是个将亡值,反正你都要亡了,我的目的是跟你有一样大的空间
		//不如把你的空间给我
		cout << "String(String&& s)-移动拷贝构造-效率高" << endl;
		swap(_str, s._str);
	}

	//s3 = s4
	String& operator=(const String& s)
	{
		cout << "String& operator=(const String& s)-拷贝赋值-效率低" << endl;

		if (this != &s)
		{
			char* newstr = new char[strlen(s._str) + 1];
			strcpy(newstr, s._str);

			delete[] _str;
			_str = nullptr;
		}

		return *this;
	}

	//s3 = 右值-将亡值
	String& operator=(String&& s)
	{
		cout << "String& operator=(const String&& s)-移动赋值-效率高" << endl;
		swap(_str, s._str); //直接掠夺s的资源即可,反正你s都要亡了

		return *this;
	}
	
	//第二个层次的问题
	//s1 + s2
	String operator+(const String& s2)
	{
		String ret(*this);
		//ret.append(s2._str); //因append我们没有模拟实现,故这里注释掉

		return ret;	//返回的是右值
	}

	//s1 += s2
	String& operator+=(const String& s2)
	{
		//this->append(s2);

		return *this; //返回的是左值
	}

	~String()
	{
		delete[]_str;
	}
private:
	char* _str;
};

String f(const char* str)
{
	String tmp(str);
	return tmp; // 返回tmp拷贝的临时对象
}


int main()
{
	String s1("左值");
	String s2(s1);				 //参数是左值
	//String s3(String("右值"));  //编译器会优化掉
	String s3(f("右值-将亡值"));	  //参数是右值-将亡值(传给你用,用完我就析构了),但编译器也会优化掉
	String s4(move(s1));			

	String s5("zuo值");
	s5 = s1;

	String s6("s6");
	String s7("s7");

	String s8 = s6 += s7; //拷贝构造
	String s9 = s6 + s7;  //移动构造

	return 0;

①、拷贝构造和移动拷贝构造的场景 (可以减少拷贝)

移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不 用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己

 注:正常的左值引用时拷贝构造,而右值引用是移动拷贝构造

 ②、拷贝赋值和移动赋值的场景与①类似(也可以减少拷贝)

③、左值和右值做返回值的场景

 operator+与operator+=的返回值

注:operator+返回的是一个右值,因为既有拷贝构造又有移动构造,编译器会选择最匹配的参数调用,用这个右值构造s9,就会匹配调用移动构造。这里其实是个移动语义。

 总结:

以前我们写的函数总是避免用传值做返回值,因为会有深拷贝,但这里有右值引用后,会有移动构造和移动赋值减少拷贝,即不会深拷贝了,那你想传值返回就传值返回(很便利)

 ④、所有深拷贝类(vector/list/map/set..),都可以加两个右值引用做参数的移动拷贝和移动赋值 

  

总结:

⑤、右值引用做函数参数,减少拷贝 

 

 ⑥、左值引用和右值引用减少拷贝的对比


 6、完美转发

模板中的&& 万能引用

解决:利用完美转发,std::forward 完美转发在传参的过程中保留对象原生类型属性

完美转发实际中的使用场景:
list的模拟实现中
template<class T>
struct ListNode
{
    ListNode* _next = nullptr;
    ListNode* _prev = nullptr;
    T _data;
};
template<class T>
class List
{
    typedef ListNode<T> Node;
public:
 List()
 {
    _head = new Node;
    _head->_next = _head;
    _head->_prev = _head;
 }
 void PushBack(T&& x)
 {
    //Insert(_head, x);
    Insert(_head, std::forward<T>(x));
 }
 void PushFront(T&& x)
 {
    //Insert(_head->_next, x);
    Insert(_head->_next, std::forward<T>(x));//复用Insert中可能丢失右值属性,故完美转发
 }
 void Insert(Node* pos, T&& x)
 {
    Node* prev = pos->_prev;
    Node* newnode = new Node;
    newnode->_data = std::forward<T>(x); // 关键位置
    // prev newnode pos
    prev->_next = newnode;
    newnode->_prev = prev;
    newnode->_next = pos;
    pos->_prev = newnode;
 }
 void Insert(Node* pos, const T& x)
 {
    Node* prev = pos->_prev;
    Node* newnode = new Node;
    newnode->_data = x; // 关键位置
    // prev newnode pos
    prev->_next = newnode;
    newnode->_prev = prev;
    newnode->_next = pos;
    pos->_prev = newnode;
 }
private:
    Node* _head;
};
int main()
{
    List<bit::string> lt;
    lt.PushBack("1111");
    lt.PushFront("2222");
    
    return 0;
}

7、新的类功能

7.1默认成员函数

原来C++类中,有6个默认成员函数:
1. 构造函数
2. 析构函数
3. 拷贝构造函数
4. 拷贝赋值重载
5. 取地址重载
6. const 取地址重载
最后重要的是前 4 个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。
C++11 新增了两个:移动构造函数和移动赋值运算符重载。
针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:
①、 如果你没自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类
型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
如果实现了就调用移动构造,没有实现就调用拷贝构造。
②、 如果你没自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
置类型成员会执行逐成员按字节拷贝自定义类型成员,则需要看这个成员是否实现移动赋
值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。 ( 默认移动赋值跟上面移动构造
完全类似 )
③、 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

7.2强制生成默认函数的关键字default:

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原 因这个函数没有默认生成。
①、有拷贝构造导致的编译器无法生成默认构造函数
class A
{
public:

    A(const int& a)
		:_a(a)
	{}

	//因为你写了拷贝构造,编译器就不会生成默认构造了
	//法一、自己写一个默认构造
	//法二、default:指定编译器显式的生成(C++11做法)
	A() = default; 

private:
	int _a = 10;
};

int main()
{
	A aa1;     //若不用default,则失败
	A aa2(aa); //成功

	return 0;
}

②、有拷贝构造导致的编译器无法生成移动构造

我们可以 使用 default关键字显示指定移动构造生成
class Person
{
public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{}

	Person(Person&& p) = default;
private:
	string _name;
	int _age;
};
int main()
{
	Person s1;
	Person s2 = s1;
	Person s3 = std::move(s1);
	return 0;
}

7.2禁止生成默认函数的关键字delete:

如果能想要限制某些默认函数的生成,在 C++98 中,是该函数设置成 private ,并且只声明补丁
已,这样只要其他人想要调用就会报错。在 C++11 中更简单,只需在该函数声明加上 =delete
可,该语法指示编译器不生成对应函数的默认版本,称 =delete 修饰的函数为删除函数。
class A
{
public:
	A() = default; 

	//若要求A的对象不能拷贝和赋值(防拷贝)

	//C++98的做法:只给声明,不给实现,这样别人就无法拷贝对象
	//缺陷:导致链接不上,且别人可以再类外定义
//	A(const int& a); 
//	A& operator=(const A& aa);

	//为解决上面缺陷,private限定,类外也无法定义
//private:
//	A(const int& a);
//	A& operator=(const A& aa);

	//C++11的做法:用delete定义为删除函数
	A(const int& a) = delete;
	A& operator=(const A& aa) = delete;

	A(const int& a)
		:_a(a)
	{}

private:
	int _a = 10;
};

int main()
{
	A aa1;
	A aa2(aa1);
	aa1 = aa2;

	return 0;
}

C++【下】链接:【C++】C++11【下】lambda表达式|thread线程库-CSDN博客

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

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

相关文章

怎么让重要文件自动备份到OneDrive?

可以让文件自动备份到OneDrive吗&#xff1f; OneDrive是比较受欢迎的云存储之一&#xff0c;主要用于存储文件和个人数据&#xff0c;随时随地都能够在多个设备&#xff08;例如Android、台式机或笔记本电脑、平板电脑等&#xff09;之间同步和共享文件。 因此&…

Python实验五 异常处理

实验 1&#xff1a;为下列代码添加异常处理。 xint(input(请输入一个整数)) print(100/x) # 实验 1&#xff1a;为下列代码添加异常处理。 try:xint(input(请输入一个整数&#xff1a;))print(100/x) except ValueError:print(请输入一个整数) except ZeroDivisionError:print…

操作系统 day05(体系结构、开机过程、虚拟机)

一&#xff0c;操作系统的体系结构 内核 内核是操作系统最基本、最核心的部分&#xff0c;实现操作系统内核功能的那些程序就是内核程序这其中&#xff1a;时钟、中断、原语是与硬件关联最紧密的模块&#xff0c;而进程管理、存储器管理、设备管理更多的是对数据结构的操作&…

【Midjourney入门教程1】Midjourney的注册、订阅

文章目录 前言一、Midjourney是什么二、Midjourney注册三、新建自己的服务器四、开通订阅 前言 AI绘画即指人工智能绘画&#xff0c;是一种计算机生成绘画的方式。是AIGC应用领域内的一大分支。 AI绘画主要分为两个部分&#xff0c;一个是对图像的分析与判断&#xff0c;即“…

【Redis】的简介和安装配置(Linux和windows)及操作命令

目录 一、概述 1.介绍 2.特点 二、安配 1. 安装 2. 配置 3. 主机连接 1.Linux连接 2.windows连接 三、命令 1. 字符串(String) 2. 哈希(Hash) 3. 列表&#xff08;List&#xff09; 4. 集合&#xff08;Set&#xff09; 一、概述 1.介绍 Redis是一个开源的、基…

EViews| 基础操作 备战下周机考

目录 一、创建工作文件 1、非时间序列数据 2、时间序列数据 二、导入数据 1、导入数据 2、保存数据组合或方程结果 三、估计回归模型 1、估计回归模型 2、回归结果名词解读 四、检验模型设定错误 1、检验是否遗漏变量 2-1、检验是否加入了不相干变量 2-2、惩罚新增…

2023年最新版潮乎盲盒源码含搭建教程

后台开发语言&#xff1a;后端 Laravel 框架开发 前端开发框架&#xff1a;uniappvue 环境配置: php7.4 mysql5.6 nginx1.22 redis&#xff08;建议宝塔面板或 lnmp&#xff09; 源码获取请自行百度&#xff1a;一生相随博客 一生相随博客致力于分享全网优质资源&#x…

大数据与健康:技术助力医疗卫生事业腾飞

大数据与健康&#xff1a;技术助力医疗卫生事业腾飞 随着科技的飞速发展&#xff0c;大数据技术已经渗透到我们生活的方方面面&#xff0c;包括医疗卫生领域。本文将对大数据在健康医疗领域的应用进行分析&#xff0c;并通过数据图表展示其发展趋势和前景。 一、背景介绍 近…

IPv4首部格式

IPv4首部格式 IPv4数据报的首部格式及其内容是实现IPv4协议各种功能的基础。 在TCPIP标准中&#xff0c;各种数据格式常常以32比特(即4字节)为单位来描述。 IPv4首部格式图 ## IPv4数据报的组成 主要由固定部分(20字节)可变部分(最大40字节) - 固定部分是指每个IPv4数据报都必…

Jmeter调用测试片段 —— 模块控制器

可以使用模块控制器调用测试片段。模块控制器提供了一种在运行时将测试片段替换为当前测试计划的机制。测试片段可以位于任何线程组中。 1、打开一个Jmeter窗口&#xff0c;添加好线程组、用户定义变量、模块控制器、测试片段、察看结果树。 2、用户定义变量同样定义好访问ip及…

ETHERNET/IP转RS485/RS232自由协议网关连接AB系统的简单配置方法

想将ETHERNET/IP网络和RS485/RS232总线连接起来吗&#xff1f;来看这款通讯网关&#xff01; 捷米特JM-EIP-RS485/232是一款通讯网关&#xff0c;它具有将ETHERNET/IP网络和RS485/RS232总线连接起来的功能。作为ETHERNET/IP网络的从站&#xff0c;它可以连接AB、欧姆龙等品牌的…

游戏反Xposed框架解决方案

在游戏安全对抗过程中&#xff0c;除了常见的内存修改、加速、破解等作弊手段&#xff0c;还有一类危害严重的外挂——「注入挂」。 据FairGuard游戏安全数据统计&#xff0c;在游戏面临的众多安全风险中&#xff0c;注入挂的占比高达17% 。如此高的占比&#xff0c;可见注入挂…

软件测试工程师必须掌握的Linux常用命令

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

msvcp120.dll下载修复详细方法与解决方法

MSVCP120.dll文件丢失是一个常见的问题&#xff0c;它通常会导致某些程序无法正常运行。这个问题可能是由于多种原因引起的&#xff0c;例如系统更新、软件卸载或病毒感染等。在这篇文章中&#xff0c;我将为您提供四种解决MSVCP120.dll文件丢失的方法&#xff0c;帮助您快速恢…

【Redis】入门篇--安装以及常用命令

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Redis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Redis是什么 二. Redis有什么优势 三…

一秒文件搜索神器—Everything,结合内网穿透成为在线搜索神器!

Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问 文章目录 Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 前…

快速灵敏的 Flink1

一、flink单机安装 1、解压 tar -zxvf ./flink-1.13.2-bin-scala_2.12.tgz -C /opt/soft/ 2、改名字 mv ./flink-1.13.2/ ./flink1132 3、profile配置 #FLINK export FLINK_HOME/opt/soft/flink1132 export PATH$FLINK_HOME/bin:$PATH 4、查看版本 flink --version 5、…

[GitLab] 安装Git 指定版本

卸载旧版本 检查是否已经安装 git --version如果已经安装&#xff0c;先卸载 yum -y remove git安装新版本 在GitHub上选择需要下载的版本 Git版本 在/usr/local/目录下新建文件夹&#xff1a;git&#xff0c;并在/usr/local/git/文件夹内下载压缩包 wget https://github…

llava1.5模型安装、预测、训练详细教程

引言 本博客介绍LLava1.5多模态大模型的安装教程、训练教程、预测教程&#xff0c;也会涉及到hugging face使用与wandb使用。 源码链接:点击这里 demo链接:点击这里 论文链接:点击这里 一、系统环境 ubuntu 20.04 gpu: 2*3090 cuda:11.6 二、LLava环境安装 1、代码下载…

数据库的增删查改(一)

Mysql的基本操作 一. 新增1.单行数据全列插入 2.多行数据指定列插入二.查询1.全列查询2.指定列查询3.查询字段为表达式4.别名5.去重6.排序7.条件查询 一. 新增 1.单行数据全列插入 表示在SQL语句中一行一行插入. 2.多行数据指定列插入 二.查询 1.全列查询 全列查询就是将val…