【C++学习】日期类和内存管理

news2024/9/20 6:20:20

🐱作者:一只大喵咪1201
🐱专栏:《C++学习》
🔥格言:你只管努力,剩下的交给时间!
图

日期类的实现和内存管理

  • 🏬日期类的实现
  • 🏬C/C++内存分布
  • 🏬C++内存管理方式
    • 🏩new/delete和malloc/free的区别
  • 🏬new和delete的实现原理
    • 🏩operator new和operator delete函数
  • 🏬定位new表达式
  • 🏬总结

🏬日期类的实现

在前面学习完整个类和对象后,接下来本喵带大家写一个日期类来练练手。

这个日期类的内容包括,四大默认函数,日期+=天数,日期+天数,日期-天数,日期-=天数,前置++,后置++,后置–,前置–,>运算符重载,==运算符重载,>=运算符重载,<运算符重载,<=运算符重载,!=运算符重载,日期-日期 返回天数。

日期类的实现由于比较简单,仅是一些基础的知识的运用,所以本喵这里就不进行详细讲解了,在代码的注释中也有相应的解释。

Date.h中的代码:

#include <iostream>
using namespace std;

class Date
{
public:
	friend ostream& operator<<(ostream& out, const Date& d);
	//构造函数
	Date(int year = 1970, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	//析构函数,对于日期类来说,并没有什么用
	~Date()
	{
		_year = 0;
		_month = 0;
		_day = 0;
	}
	//拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//复制运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
	
	//获取每个月的天数
	int GetMonthDay(int year, int month)
	{
		int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2)
		{
			if ((year % 4 == 0 && year % 100) || (year % 400))
				return 29;
		}
		return arr[month];
	}
	
	//日期+=天数
	Date& operator+=(int day);
	//日期+天数
	Date operator+(int day);
	//日期-=天数
	Date& operator-=(int day);
	//日期-天数
	Date operator-(int day);
	//前置++
	Date& operator++();
	//后置++
	Date operator++(int);
	//前置--
	Date& operator--();
	//后置--
	Date operator--(int);
	//==运算符重载
	bool operator==(const Date& d) const;
	//!=运算符重载
	bool operator!=(const Date& d) const;
	//>运算符重载
	bool operator>(const Date& d) const;
	//<=运算符重载
	bool operator<=(const Date& d) const;
	//<运算符重载
	bool operator<(const Date& d) const;
	//>=运算符重载
	bool operator>=(const Date& d) const;
	//日期-日期 返回天数
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

//流插入运算符重载
ostream& operator<<(ostream& out, const Date& d);
  • 在头文件中,有的函数是有定义的,想构造函数,析构函数,拷贝构造函数,赋值运算符重载函数,以及获取天数的函数。
  • 因为这些函数会频繁的调用,而定义在类中的函数,编译器会把它当作内联函数处理,因为这些函数调用比较频繁,所以放在类中以减少系统的开销。
  • 而对于那些不常调用的成员函数,在类中只写函数的声明。

Date.cpp中的代码:

#include "Date.h"

//日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		int tmp = GetMonthDay(_year, _month);
		_day -= tmp;
		if (_month == 12)
		{
			_year++;
			_month = 1;
		}
		else
		{
			_month++;
		}
	}
	return *this;//日期本身被修改了
}

//日期+天数
Date Date::operator+(int day)
{
	Date ret(*this);
	ret._day += day;
	while (ret._day > GetMonthDay(_year, _month))
	{
		int tmp = GetMonthDay(ret._year, ret._month);
		ret._day -= tmp;
		if (ret._month == 12)
		{
			ret._year++;
			ret._month = 1;
		}
		else
		{
			ret._month++;
		}
	}
	return ret;//日期本身没有被修改
}

//日期-=天数
Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		if (_month == 1)
		{
			_year--;
			_month = 12;
		}
		else
		{
			_month--;
		}
		int tmp = GetMonthDay(_year, _month);
		_day += tmp;
	}
	return *this;
}

//日期-天数
Date Date::operator-(int day)
{
	Date ret(*this);
	ret._day -= day;
	while (ret._day <= 0)
	{
		if (ret._month == 1)
		{
			ret._year--;
			ret._month = 12;
		}
		else
		{
			ret._month--;
		}
		int tmp = GetMonthDay(ret._year, ret._month);
		ret._day += tmp;
	}
	return ret;
}

//前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//后置++
Date Date::operator++(int)
{
	Date ret(*this);
	*this += 1;
	return ret;
}

//前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

//后置--
Date Date::operator--(int)
{
	Date ret(*this);
	*this -= 1;
	return ret;
}

//==运算符重载
bool Date::operator==(const Date& d) const
{
	return (_year == d._year) && (_month == d._month) && (_day == d._day);
}

//!=运算符重载
bool Date::operator!=(const Date& d) const
{
	return !((_year == d._year) && (_month == d._month) && (_day == d._day));
}

//>运算符重载
bool Date::operator>(const Date& d) const
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year && _month > d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day > d._day)
	{
		return true;
	}
	return false;
}

//<=运算符重载
bool Date::operator<=(const Date& d) const
{
	return (!(*this > d));
}
//<运算符重载
bool Date::operator<(const Date& d) const
{
	return (!(*this >= d));
}

//>=运算符重载
bool Date::operator>=(const Date& d) const
{
	return (*this > d || *this == d);
}
//日期减日期
int Date::operator-(const Date& d)
{
	int count = 0;
	int flag = 1;
	Date max = *this;
	Date min = d;
	int ret = max < min;
	if (ret)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	while (min < max)
	{
		++min;
		count++;
	}
	return flag * count;
}

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
  • 成员函数不在类中定义,而在cpp源文件中定义时,需要在函数名的前面加上类名和域作用限制符::(Date::函数名)。
  • 凡是不会修改this指针指向内容的成员函数,都应该使用const修饰。

test.cpp中的测试代码:

#include "Date.h"

int main()
{
	//测试日期加天数
	Date d1(2022, 10, 31);
	cout << d1 + 100 << endl;

	//测试日期减天数
	Date d2(2022, 11, 6);
	cout << d2 - 10 << endl;

	//测试前后置加加
	Date d3;
	cout << d3++ << endl;
	cout << ++d3 << endl;

	//测试日期相减
	Date d4 = d2;
	Date d5 = 2022;
	cout << d4 - d5 << endl;
	return 0;
}

图
部分测试结果,大家可以自己下去试试。

🏬C/C++内存分布

在学习C语言的时候,我们知道内存是分为很多个区的,有栈区,堆区,静态区,常量区等等,这是站在C语言的角度来看的.

C++是在建立在C语言的基础上的,所以C++和C语言的内存管理的方式是一样的,但是此时并不站在语言本身的角度去看内存,而是站在系统的角度去看内存。

图
上图就是将内存划分的几个区,其中数据段就是C语言中的静态区,代码段就是C语言中的常量区。不同区中的数据有不同的性质,比如生命周期,作用域等等性质。

  • 内核空间:是用来跑操作系统的,系统级别的数据都是在这个区上的,而且这个区我们普通用户是无法进行读写的,它从硬件上就给操作系统提供了保护。
  • 栈区:又叫堆栈,是用来存放局部变量的,这些变量都是些临时变量,比如非静态局部变量/函数参数/返回值等等,在用到的时候会开辟内存空间,用完以后该空间就会还给操作系统,这些变量的作用域和生命周期也是局部的,并且在开辟空间的时候是向下增长的,也就是先从高地址处开辟空间,再向低地址处开辟空间。
  • 内存映射段:是用来进行文件操作,以及动态库等内容的操作的,这个部分这里暂时先不谈。
  • 堆区:是用来存放动态变量的,这些变量在开辟内存空间的时候,往往是用多少开辟多少,而且空间大小还可以调整,在使用完以后需要手动将这些空间释放掉,否则就会造成内存泄漏,在开辟内存空间的时候,是向上生长的。
  • 数据段:是用来存放全局变量,以及使用static修饰的变量的,这些变量一旦被创建,它们的生命周期就是整个程序的生命周期,只有程序结束以后才会结束,所以在程序它是一个共享变量,因为对它的操作结果是会累加的。
  • 代码段:是用来存放代码以及那些字符常量的,这部分内容是不可以被修改的,只能读取使用,但是存放的并不是我们写好的源文件中的内容,而是经过编译链接以后产生的计算器可以读懂的机器码。

上面这些仅是本喵的一个感性认识,具体的特性还需要在具体的情况中去体会。

图
上图中,将代码中的变量和内存的各个区域一一对应,可以很清楚的看到什么类型的变量放在内存的什么区域。

下面跟着本喵做一个练习题,代码如下:

int globalvar = 1;
static int staticGlobalVar = 1;

void test()
{
	static int staticVar = 1;
	int localvar = 1;
	int num1[10] = { 1,2,3,4 };
	char char2[] = "abcd";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 8);
	free(ptr1);
	free(ptr3);
}

来看一组问题(本喵这里就直接回答了):

  • 变量globalvar是一个全局变量,所以它是存在数据段的(静态区),作用域和生命周期也是全局。
  • 变量staticGlobalVar是用static修饰的全局变量,也是存在数据段的,作用域和生命周期也是全局。
  • 变量staticVal是被static修饰的局部变量,存放在数据段,生命周期是全局的,作用域是test函数内。
  • 变量localvar是一个局部变量,是存放在栈区的,也就是堆栈中,生命周期和作用域都是是test函数内。
  • 变量num1是一个数组,也是临时变量,是存放在栈区的,生命周期和作用域都是是test函数内。
  • 变量char2同样是一个数组,该数组中的字符是从常量区复制到栈区的,所以存放在栈区,生命周期和作用域都是是test函数内。
  • *char2是数明名的解引用,得到的结果就是数组中的第一个字符a,同样是在栈区。
  • pChar3是一个被const修饰的指针变量,仍然是一个临时变量,存放在栈区。
  • Pchar3里面的值是字符a在常量区的地址,所以*Pchar3后得到的值就是在常量区中的字符a,所以是放在常量区的,生命周期和作用域是一直存在的。
  • ptr1是一个指针变量,也是一个临时变量,存放在栈区。
  • *ptr1中的内容是动态开辟空间的地址,所以是放在堆区的,它的生命周期和作用域是视情况而定的。

通过上面详细分析各个变量的类型以及它们在内存中的位置,相信大家对内存管理的理解更加深刻了。

🏬C++内存管理方式

在C语言中,内存的管理是通过malloc,calloc,realloc等函数来实现的,由于C++兼容C语言,所以这些函数在C++中仍然可以使用,但是C++中也提出了新的内存管理方式,就是运算符new和delete。

int main()
{
	//动态申请一个int类型的空间
	int* p1 = new int;
	//动态申请一个int类型的空间,并且初始化为10
	int* p2 = new int(10);
	//动态申请10个int类型的空间
	int* p3 = new int[10];
	//动态申请10个int类型的空间并初始化
	int* p4 = new int[10]{ 1,2,3,4,5,6,7,8,9,10 };

	//释放p1和p2分别指向空间
	delete p1;
	delete p2;
	//释放p3和p4分别指向的空间
	delete[] p3;
	delete[] p4;

	return 0;
}

上面是它的用法。

图
再结合一张图片来说明。

多个对象初始化时候,不能使用(),而是要和数组一样,使用{},但是没有引号。

注意:

申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]。必须匹配起来使用。

虽然不匹配的情况下,有时也不会报错,但是原则上我们还是要匹配使用的,有兴趣的小伙伴可以自行研究不配合会怎样。

在上面的代码中,我们发现,它的作用和malloc等函数是一样的,但实际上它们还是有差别的。

🏩new/delete和malloc/free的区别

  1. new/delete是关键字,属于运算符,而malloc/free是函数

图
上图中,使用malloc和new做同样的事情,malloc需要传参,但是new却不需要,因为malloc是函数,调用函数需要传参,而new是关键字,是运算符,使用的时候不需要传参,free和delete同理。

  1. new会调用自定义类型的构造函数,delete会调用自定义类型的析构函数,而malloc/free不会。

new和delete之所以在C++中会存在,那就肯定有和malloc和free不同的地方。C++是基于面向对象的语言,所以new和delete也是为了处理自定义类型才有的。在处理内置类型的时候,new和malloc是一样的,没有区别,delete和free也是。

图
创建这样一个类,在类中显示定义构造函数和析构函数,并且在函数内打印对应的语句。

图
使用new开辟一个A类型的动态空间时,会自动调用A的构造函数,来给动态空间中的对象初始化。这一点和使用calloc开辟动态空间后用0初始化类似,只是这里调用的是构造函数。

图
是使用delete释放A类型的动态空间时,会自动调用A的析构函数。

new/delete 和 malloc/free最大区别是 new/delete对于自定义类型除了开空间还会调用构造函数和析构函数。

图
使用new开辟多个动态空间时,就会调用多次构造函数来初始化,当使用delete释放多个动态空间时,同样也会调用多次析构函数。

  1. new开辟空间失败会抛异常,malloc开辟失败返回空指针

先看malloc开辟空间失败的情况,当开辟的空间很大的时候,系统的内存不够,就会开辟失败。

图
每次开辟1G的动态空间,并且不释放,第一次开辟成功,第二次就失败了,因为此时内存不够用了。

  • 打印出开辟失败的原因是,开辟失败后返回的指针是NULL空指针,所以才能符号调节判断,进入开辟失败打印。

再看使用new开辟失败后的情况。

图
同样每次开辟1G的内存空间,第一次开辟成功,第二次就失败了。

  • 打印出的结果不是开辟失败,而是出现异常,说明开辟失败以后并不是返回NULL空指针,所以就没有进if判断语句,而是直接跳到了catch中。
  • try和catch就是专门用来捕获程序中的异常的,如上图中的蓝色圈,以后会相信介绍异常,这里仅需要知道,new开辟失败了以后是抛异常。

🏬new和delete的实现原理

🏩operator new和operator delete函数

是不是感觉很眼熟,这个不是运算符重载吗?不是,这里是俩个函数。

  • operator new和operator delete是系统提供的全局函数。
  • new在底层调用operator new全局函数来申请空间。
  • delete在底层通过operator delete全局函数来释放空间。

图
上图中的代码是从C++的库中扒出来的,可以看到,operator new函数的实质就是在使用malloc开辟动态空间,开辟成功则返回地址,开辟失败则抛出异常,如上图中的红色线。

图
上图中的代码同样是从C++的库中扒出来的,可以看到,在最下面的红色框中,将free§宏定义为_free_dbg(),在倒数第二个红色框中,又使用了宏定义后的函数来释放空间,也就是使用了free()函数来释放空间。

以上库封装后的代码可以总结为:

  • operator new函数的本质是在使用malloc开辟动态内存空间。
  • operator delete函数的本质是在使用free释放开辟好的动态内存空间。

下面我们来看new的底层原理:

图
以该段代码为例,我们来看它的汇编代码:
图

  • 在使用new开辟一个A类型的动态空间的时候,在汇编代码中可以看到,调用了operator new函数和A类型的构造函数。
  • 在使用delete释放刚刚开辟的空间时,在汇编代码中调用了如上图中最后一个绿色框中所示的函数,在该函数内会调用operator delete函数和A类型的析构函数。

结合operator new函数和operator delete函数的本质,我们就可以得出结论,

  • new的本质就是:使用malloc开辟空间,成功了返回地址,失败了抛异常,并且调用自定义类型的构造函数。
  • delete的本质就是:使用free释放开辟的空间,并且调用自定义函数的析构函数。

同样的,使用new开辟多个空间,和使用delete释放多个空间,无非就是多调用几次operator new和构造函数,以及operator delete和析构函数。

图
来看它的汇编代码:
图

  • 调用了operator new[]函数,该函数多了一个[],无非就是多调用几次operator new函数,具体次数又[]中的数字决定。
  • 在第二个绿色框内,通过迭代器调用了多次构造函数。
  • delete[]同理,本喵这里就不列出来了。

所以说,无论是开辟一个自定义类型的动态空间,还是多个,其本质都是在调用malloc和构造函数。在释放的时候,本质也是在调用free函数和析构函数。

🏬定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

  • 用法:new(空间地址)类型(类型初始化列表)
  • 功能:将没有初始化的动态内存空间进行初始化
class A
{
public:
	A(int a = 10)
		:_a(a)
	{
		cout << "构造函数" << endl;
	}

private:
	int _a;
};

int main()
{
	A* pa = (A*)malloc(sizeof(A));
	if (pa == nullptr)
	{
		perror("malloc fail");
		return -1;
	}

	return 0;
}

上面代码中,使用malloc函数开辟了一个类型A的动态空间。
图
通过调试可以看到,此时动态空间中成员变量a的值是随机值,因为malloc开辟的动态空间并不会自动进行初始化。

图
此时使用定位new以后,就成功的将原本是随机数的动态空间通过调用类A的构造函数初始化为了20。

结合前面的知识,可以模拟一下new和delete的实现:
图

  • new的实现本质就是在调用operator new函数和构造函数,而定位new同样也会调用构造函数。
  • delete的本质就是在调用operator delete函数和析构函数,而operator delete函数的本质也是在调用free函数。

定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

🏬总结

日期类的实现仅是对前面学习内容的一个应用,而在C++的内存管理中,仅需要知道new/delete和malloc/free的区别,以及new和delete的实现原理即可。

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

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

相关文章

【工具】Git-码农“吃饭的碗”要拿好

汝之观览&#xff0c;吾之幸也&#xff01;本文主要讲解的是Git的轻巧使用&#xff08;创建、下载、上传、更新、回退&#xff09;&#xff0c;我们平常都是通过idea自带的git工具&#xff0c;或者其他工具来拉取提交代码&#xff0c;这里主要用命令行的方式拉取代码&#xff0…

基于springboot+vue的心理预约咨询测试交流小程序

&#x1f496;&#x1f496;作者&#xff1a;IT跃迁谷毕设展 &#x1f499;&#x1f499;个人简介&#xff1a;曾长期从事计算机专业培训教学&#xff0c;本人也热爱上课教学&#xff0c;语言擅长Java、微信小程序、Python、Golang、安卓Android等。平常会做一些项目定制化开发…

【REST系列】详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献

文章目录REST详解词组解释论文摘要REST架构约束一、Client–server&#xff1a;客户端-服务器二、Stateless&#xff1a;无状态三、Cacheability&#xff1a;缓存四、⭐Uniform Interface&#xff1a;统一接口 (RESTful API)五、Layered System&#xff1a;分层系统六、Code-On…

荧光生物标记物510758-19-7,5-羧基荧光素-炔烃,5-FAM alkyne

5-FAM-Alkyne 是一种高选择性和灵敏的荧光生物标记物&#xff0c;可用于标记碱性磷酸酶 (ALP)。炔烃可以通过铜催化的点击化学与多种叠氮化合物共轭。&#xff08;西安凯新生物科技有限公司​所有的试剂仅用于科研实验&#xff0c;不可用于人体试验&#xff09; 5-FAM Alkyne …

【Hadoop】P2 Hadoop简介

Hadoop是什么 Hadoop为分布式系统基础框架。主要解决海量数据的存储和海量数据的分析计算问题。 大数据解决的是海量数据的采集、存储和计算。 Hadoop三大发行版本 Apache 最原始最基础的版本&#xff0c;2006年诞生&#xff0c;开源&#xff1b; Cloudera 内部封装Apache&am…

HTML中华传统文化题材网页《中国民间年画》HTML+CSS+JavaScript

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Redis网络模型-IO多路复用

Redis网络模型-IO多路复用 系统IO交互 IO多路复用概念 文件描述符&#xff08;File Descriptor):简称FD&#xff0c;是一个从O开始递增的无符号整数&#xff0c;用来关联Linux中的一个文件。在Linux中&#xff0c;一切皆文件&#xff0c;例如常规文件、视频、硬件设备等&…

卷积神经网络的卷积层

文章目录卷积核正向传播反向传播参考文献附录卷积核 笔者在学会了如何运用卷积神经网路后&#xff0c;突然有一天萌发了很多问题&#xff0c;为什么要用卷积核&#xff1f;卷积核具体完成了什么工作&#xff1f;带着这些疑问&#xff0c;笔者开始查询资料&#xff0c;其中一段视…

MongoDB入门与实战-第一章-介绍

目录参考一、介绍二、概念三、预留默认库四、 MongoDB 集合五、 MongoDB 视图六、MongoDB 索引七、MongoDB ObjectIdMongoDB 性能问题定位方式参考 MongoDB 基础浅谈 一、介绍 MongoDB是为快速开发互联网Web应用而设计的数据库系统。 MongoDB的设计目标是极简、灵活、作为We…

[vue3] Tree/TreeSelect树形控件使用

✨✨个人主页:沫洺的主页 &#x1f4da;&#x1f4da;系列专栏: &#x1f4d6; JavaWeb专栏&#x1f4d6; JavaSE专栏 &#x1f4d6; Java基础专栏&#x1f4d6;vue3专栏 &#x1f4d6;MyBatis专栏&#x1f4d6;Spring专栏&#x1f4d6;SpringMVC专栏&#x1f4d6;SpringBoot专…

【定语从句练习题】That 、who、whom、省略

1. 改写训练 1.I’d like to speak to the person that wrote this letter. 主 2.The tomatoes that I bought yesterday. 宾&#xff0c;可以去掉 3.Joe’s got a motorbike that can do 200Km an hour. 主 4.Is that the computer that doesn’t work. 主 5.Those are trous…

[操作系统笔记]处理机调度

调度算法 名称英文作业调度进程调度说明特点先来先服务First-come first-served, FCFS适用适用按作业到达先后顺序&#xff08;即优先考虑等待时间最长的&#xff09;非抢占式短作业优先short job first, SJF适用适用作业越短&#xff08;即运行时间越短&#xff09;优先级越高…

SpringBoot异常:Process finished with exit code 0 | Tomcat服务没有启动 | 无法通过浏览器访问

错误信息 启动springBoot项目后&#xff0c;打印信息如下 意思是&#xff1a;我该执行的程序已执行完毕&#xff0c;并正常退出。 希望提示&#xff1a;打印Tomcat已在8080端口启动&#xff0c;可以通过浏览器访问&#xff0c;如果是这个问题&#xff0c;继续向下浏览&#xf…

标准库类型string和vector

一、命名空间 std::cinstd就是命名空间&#xff0c; 这个的含义是 &#xff1a;编译器应该从操作符左侧的名字所示的作用域std中去寻找cin。 另一种方式就是在开头显式进行说明&#xff1a; using std::cin;这样一来后续就不用再去在每条语句中显式说明了。 需要注意的是&…

微信小程序实战 wx.showNavigationBarLoading(),下拉动画配置无效

文章目录前情提要原因分析实战解析最后前情提要 下拉刷新一定是移动端常用操作&#xff0c;微信小程序官方集成了下拉刷新监听函数onPullDownRefresh(),以及显示下拉动画apiwx.showNavigationBarLoading(),但是我们在初次接触这个api发现&#xff0c;调用该函数动画不显示&…

头歌-信息安全技术-Spectre侧信道攻击过程验证

头歌-信息安全技术-Spectre侧信道攻击过程验证一、第1关&#xff1a;Cache vs Memory1、编程要求2、评测代码二、第2关&#xff1a;基于FlushReload的侧信道实现1、编程要求2、评测代码三、第3关&#xff1a;Spectre预测执行1、编程要求2、评测代码四、第4关&#xff1a;Spectr…

【Unity】关于升级到2021.3.12之后URP编译错误的问题

前几天&#xff0c;我一时兴起&#xff0c;把Unity从2021.3.11 LTS 升级到 2021.3.12 LTS&#xff0c;本来以为不会有啥区别&#xff0c;然后意想不到的是&#xff0c;居然出现了编译错误&#xff1a; 我一开始以为这个就是我的工程设置有问题&#xff0c;然后我就就新…

前端面试之Vue专题

目录 前言 MVVM模式 Vue的响应式原理 路由守卫 前言 网上有许多前端八股文&#xff0c;但是缺少便于理解的说明和案例&#xff0c;需要自行查阅资料。这篇文章我就按照面试的高频题来记录自己的理解和实操。 MVVM模式 一、三者含义 M是Model&#xff0c;数据模型&#xf…

非项目活动的时间怎么跟踪?

会计、审计、合规和专业服务企业通常需要跟踪花费在项目和非项目上的时间以进行报告。员工可以使用8Manage工时表这样的工具来获取与项目和非项目任务相关的工作时间&#xff0c;并记录管理时间。 非项目时间类别确定在项目工作之外发生的不同类型的活动。你可以在工时表解决方…

【网络篇】第六篇——网络套接字编程(二)(UDP详解)

基于UDP协议的套接字程序 服务端 服务端创建套接字 服务的绑定 字符串IP VS 整数IP 运行服务器 客户端 客户端创建套接字 客户端绑定 启动客户端 本地测试 INADDR_ANY 简易的回声服务器 网络测试 基于UDP协议的套接字程序 服务端 服务端创建套接字 我们把服务…