C++基础11:模板与命名空间

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C C {\rm C} C++精通面向对象编程》(曾凡锋等)。



10.模板与命名空间
10.1 模板简述
  • 模板使函数和类的处理对象参数化,使代码具有通用性;

  • C {\rm C} C++程序的组成单位是函数和类,因此,模板分为函数模板 ( f u n c t i o n t e m p l a t e ) ({\rm function\ template}) (function template)和类模板 ( c l a s s t e m p l a t e ) ({\rm class\ template}) (class template);定义模板后,可以处理不同的数据类型,不必显式定义针对不同数据类型的函数或类;

  • 模板、函数模板、类模板与对象间的关系如下:

    15

  • 模板可以最大限度地实现代码重用,使代码精简;

10.2 函数模板
  • 函数模板是一类可以被实例化的特殊函数,通过模板可以操作通用类型的数据,函数模板处理的数据类型是通过参数来体现,在函数模板实例化的过程中,才将这些参数具体化为一种特定的数据类型,因此,在定义函数时不用为每种数据类型都编写重复的相似代码;模板中表示数据类型的参数称为模板参数,这是一种特殊的参数,能传递一种数据类型;

  • 声明函数模板参数类型的语法格式:

    // 声明格式1:
    template <class 类型标识符> 返回类型 函数名(函数形参表);// 声明格式2:
    template <typename 类型标识符> 返回类型 函数名(函数形参表);
    
    • t e m p l a t e {\rm template} template是声明模板的关键字,表示声明一个模板;
    • t e m p l a t e {\rm template} template关键字后是用尖括号’<>'括起来的类型参数表,类型参数表中包含一个或多个由逗号分隔的类型参数项,每一项由关键字 c l a s s {\rm class} class和用户命名的标识符组成,此标识符为类型参数,不是一种数据类型,可以同一般数据类型一样使用在函数的任何地方;
  • 调用函数模板的语法格式:

    函数名<具体类型>(参数表);
    
  • 在调用函数模板时,<具体类型>可以省略,由系统自动判定;当<具体类型>不省略时,为显式实例化,当<具体类型>省略时,为隐式实例化;

  • 函数模板接收参数类型问题:

    // 定义一个返回两个对象中较大对象的函数模板;
    // 下面的函数模板只能接收相同参数,不能接收两个不同的参数;
    // 因为只包含了一种类型的模板参数typename TheType;
    template <typename TheType>
    TheType GetMax(TheType a,TheType b)
    {return (a>b?a:b);
    }
    
    // 下面的函数模板可以接收两个不同类型的参数;
    template <typename TheType1,typename TheType2>
    TheType1 GetMax(TheType1 a,TheType2 b)
    {return (a>b?a:b);
    }
    
  • 函数模板实例:定义一个操作数组的函数模板,完成遍历数组输出元素的功能 ( e x a m p l e 10 _ 1. c p p ) ({\rm example10\_1.cpp}) (example10_1.cpp)

    /*** 作者:罗思维* 时间:2024/03/24* 描述:定义一个操作数组的函数模板,完成遍历数组输出元素的功能*/
    #include <iostream>
    #include <string>using namespace std;// 定义函数模板;
    template <class T>
    void printArray(const T *array, const int count) {for (int i = 0; i < count; i++) {cout << array[i] << " ";}cout << endl;
    }int main() {int nArray[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};char cArray[] = {'W', 'E', 'L', 'C', 'O', 'M', 'E'};// 调用函数模板输出整型数组和字符数组中元素;printArray(nArray, sizeof(nArray) / sizeof(int));printArray(cArray, sizeof(cArray) / sizeof(char));return 0;
    }
    
  • 模板函数可以像普通函数一样被重载,实例如下 ( e x a m p l e 10 _ 2. c p p ) ({\rm example10\_2.cpp}) (example10_2.cpp)

    /*** 作者:罗思维* 时间:2024/03/24* 描述:模板函数重载。*/
    #include <iostream>
    #include <string.h>using namespace std;// 定义函数模板;
    template <typename TheType>
    TheType GetMax(TheType a, TheType b) {return (a > b ? a : b);
    }// 重载函数模板,使函数模板支持字符串的处理;
    char* GetMax(char* a, char* b) {return (strcmp(a, b) > 0 ? a : b);
    }int main() {int nNumber1 = 10, nNumber2 = 20;float fNumber1 = 13.14, fNumber2 = 5.20;char a = 'L', b = 'C';char *p1 = (char*)"C++";char *p2 = (char*)"Python";cout << "GetMax(10,20):" << GetMax(nNumber1, nNumber2) << endl;cout << "GetMax(13.14,5.20):" << GetMax(fNumber1, fNumber2) << endl;cout << "GetMax('L','C'):" << GetMax(a, b) << endl;cout << "GetMax('C++','Python'):" << GetMax(p1, p2) << endl;return 0;
    }
    
10.3 类模板
  • 类模板的作用:将类所处理的对象类型参数化,它使得类中的某些数据成员的参数和返回值能取任意数据类型;

  • 类模板定义的语法格式:

    template <类型参数表>
    class 类名
    {// 类体
    };
    
    • t e m p l a t e {\rm template} template:声明模板的关键字,表示声明一个模板类;
    • <类型参数表>中包含一个或多个类型参数项,每一项由关键字 c l a s s {\rm class} class和一个用户自定义的标识符组成,标识符为类型参数;
    • 使用类模板时,先将其实例化,即用实际的数据类型代替类型参数;
    • 当类模板中的成员函数在类定义体外定义时,必须被定义为一个函数模板的形式;
  • 类模板实战项目 ( c l a s s T e m p l a t e ) ({\rm classTemplate}) (classTemplate)

    • 项目需求:定义一个简单通用数组类模板,实现对一般数据类型数组的操作;

    • C A r r a y {\rm CArray} CArray类定义头文件 ( C A r r a y . h ) ({\rm CArray.h}) (CArray.h)

      /*** 作者:罗思维* 时间:2024/03/25* 描述:CArray类定义头文件。 */
      #pragma once
      #include <iostream>
      #include <iomanip>
      #include <string.h>using namespace std;const int MIN_SIZE = 30;// 定义模板类 
      template <class T>
      class CArray {								// 数组类; protected:T* m_pArray;						// 数组指针; int m_nSize;						// 数组元素个数; public:CArray(int nSize, T Initial);		// 构造函数,初始化数组; ~CArray() {							// 析构函数,释放内存; delete[] m_pArray;};T& operator[] (int nIndex) {		// 重载数组下标运算符; return m_pArray[nIndex];};void Show(const int nNumElems);		// 输出前nNumElems个元素; void Sort(int nNumElems);			// 将前nNumElems个元素进行排序; 
      };template <class T>
      CArray<T>::CArray(int nSize, T InitVal) {m_nSize = (nSize > 1) ? nSize : 1;		// 保证nSize不小于1; m_pArray = new T[m_nSize];for (int i = 0; i < m_nSize; i++) {m_pArray[i] = InitVal;				// 将元素全部初始化为InitVal; }
      }template <class T>
      void CArray<T>::Show(const int nNumElems) {for (int i = 0; i < nNumElems; i++) {cout << m_pArray[i] << ' ';}
      }template <class T>
      void CArray<T>::Sort(int nNumElems) {		// 对元素进行排序; int nOffset = nNumElems;bool bSorted;if (nNumElems < 2) {return;}do {nOffset = (nOffset * 8) / 11;nOffset = (nOffset < 1) ? 1 : nOffset;bSorted = true;for (int i = 0, j = nOffset; i < (nNumElems - nOffset); i++, j++) {if (m_pArray[i] > m_pArray[j]) {T nSwap = m_pArray[i];m_pArray[i] = m_pArray[j];m_pArray[j] = nSwap;bSorted = false;}}} while (!bSorted || nOffset != 1);
      }
      
    • C M y S t r i n g {\rm CMyString} CMyString类定义头文件 ( C M y S t r i n g . h ) ({\rm CMyString.h}) (CMyString.h)

      /*** 作者:罗思维* 时间:2024/03/25* 描述:CMyString类定义头文件。 */
      #pragma once
      #include "CArray.h"// 定义字符串类; 
      class CMyString {protected:char* m_pszString;					// 字符串指针; int m_nSize;						// 字符串中的字符个数; public:CMyString(int nSize = MIN_SIZE) {m_pszString = new char[m_nSize = nSize];};CMyString(const CMyString& CString);CMyString(const char* pszString);CMyString(const char cChar);~CMyString() {delete[] m_pszString;};int getLen() {return strlen(m_pszString);};int getMaxLen() {return m_nSize;};// 重载运算符= CMyString& operator=(const CMyString& aString);CMyString& operator=(const char* pszString);CMyString& operator=(const char cChar);// 重载运算符> friend operator > (CMyString& aString1, CMyString& aString2) {return (strcmp(aString1.m_pszString, aString2.m_pszString) > 0) ? 1 : 0;}friend ostream& operator << (ostream& os, CMyString& aString);
      };
      
    • C M y S t r i n g {\rm CMyString} CMyString类实现文件 ( C M y S t r i n g . c p p ) ({\rm CMyString.cpp}) (CMyString.cpp)

      /*** 作者:罗思维* 时间:2024/03/25* 描述:CArray类实现文件。 */
      #include "CMyString.h"CMyString::CMyString(const CMyString &aString) {m_pszString = new char[m_nSize = aString.m_nSize];strcpy(m_pszString, aString.m_pszString);
      }CMyString::CMyString(const char *pszString) {m_pszString = new char[m_nSize = strlen(pszString) + 1];strcpy(m_pszString, pszString);
      }CMyString::CMyString(const char cChar) {m_pszString = new char[m_nSize = MIN_SIZE];m_pszString[0] = cChar;m_pszString[1] = '\0';
      }CMyString &CMyString::operator=(const CMyString &aString) {// 检查是否有足够的空间进行字符串的复制; if (strlen(aString.m_pszString) < unsigned(m_nSize)) {strcpy(m_pszString, aString.m_pszString);} else {strncpy(m_pszString, aString.m_pszString, m_nSize - 1);}return *this;
      }CMyString &CMyString::operator=(const char *pszString) {if (strlen(pszString) < unsigned(m_nSize)) {strcpy(m_pszString, pszString);} else {strncpy(m_pszString, pszString, m_nSize - 1);}return *this;
      }CMyString &CMyString::operator=(const char cChar) {if (m_nSize > 1) {m_pszString[0] = cChar;m_pszString[1] = '\0';}return *this;
      }// 输出对象重载; 
      ostream &operator << (ostream &os, CMyString &aString) {os << aString.m_pszString;return os;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/25* 描述:程序主文件。 */
      #include <iostream>
      #include "CMyString.h"using namespace std;int main() {const int MAX_ELEMS = 10;int nArr[MAX_ELEMS] = {10, 20, 40, 50, 60, 90, 80, 70, 30, 100};char cArr[MAX_ELEMS] = {'C', 'W', 'r', 'Y', 'k', 'J', 'X', 'Z', 'y', 's'};CArray<int> IntegerArray(MAX_ELEMS, 0);			// 用int类型实例化通用数组类模板;CArray<char> CharArray(MAX_ELEMS, ' ');			// 用char类型实例化通用数组类模板;CArray<CMyString> StringArray(MAX_ELEMS, " ");	// 用自定义类型CMyString实例化通用数组类模板;for (int i = 0; i < MAX_ELEMS; i++) {IntegerArray[i] = nArr[i];}for (int i = 0; i < MAX_ELEMS; i++) {CharArray[i] = cArr[i];}StringArray[0] = "GuangDong";StringArray[1] = "BeiJing";StringArray[2] = "HuBei";StringArray[3] = "GuiZhou";StringArray[4] = "GuangXi";StringArray[5] = "HuNan";StringArray[6] = "ShanDong";StringArray[7] = "ShanXi";StringArray[8] = "JiangSu";StringArray[9] = "ZheJiang";// 输出IntegerArray排序前后的内容;cout << "Unsorted array is:" << endl;IntegerArray.Show(MAX_ELEMS);IntegerArray.Sort(MAX_ELEMS);cout << "\nSorted array is:" << endl;IntegerArray.Show(MAX_ELEMS);cout << endl;// 输出CharArray排序前后的内容;cout << "Unsorted array is:" << endl;CharArray.Show(MAX_ELEMS);CharArray.Sort(MAX_ELEMS);cout << "\nSorted array is:" << endl;CharArray.Show(MAX_ELEMS);cout << endl;// 输出StringArray排序前后的内容;cout << "\nUnsorted array is:" << endl;StringArray.Show(MAX_ELEMS);StringArray.Sort(MAX_ELEMS);cout << "\nSorted array is:" << endl;StringArray.Show(MAX_ELEMS);;return 0;
      }
      
10.4 命名空间
  • 命名空间是 A N S I C {\rm ANSI\ C} ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突;

  • C {\rm C} C++中的作用域有文件作用域、函数作用域、复合语句作用域和类作用域等,在不同的作用域中,定义具有相同名称的变量是合法的;

  • 在文件中可以定义全局变量,作用域是整个程序,在同一个作用域中不应该出现两个或多个同名的实体;

  • 在大型软件开发中,一般程序分模块完成,在各模块中可能会产生同名的实体,从而产生命名冲突;

  • 如果引用标准库、第三方库、自定义库中包含与程序中定义的全局实体同名的实体,或不同库之间有同名的实体,则编译时出现命名冲突,称为全局命名空间污染 ( g l o b a l n a m e s p a c e p o l l u t i o n ) ({\rm global\ namespace\ pollution}) (global namespace pollution)

  • 命名空间是由开发者命名的一个作用域区域,这些区域称为空间域,开发者可以根据需要指定一些有名称的空间域,把自定义的实体放在这个空间域中,保证使其与外界分离,这样可以使空间域内部实体不会与外界产生冲突;

  • 命名空间定义的语法格式:

    namespace <命名空间名>
    {...;	// 命名空间实体;
    }
    
    • n a m e s p a c e {\rm namespace} namespace:定义命名空间的关键字;
    • <命名空间名>:用户指定的命名空间的名称;
    • 大括号内是声明块,在其中声明的实体称为命名空间成员 ( n a m e s p a c e m e m b e r ) ({\rm namespace\ member}) (namespace member),命名空间成员可以包含变量、常量、结构体、类、模板、命名空间等;
  • 命名空间举例:

    namespace myns
    {int a;char c;
    }
    
    • 在程序中使用变量 a 、 c {\rm a、c} ac,需要加上命名空间名和作用域限定符" : : :: ::",如: m y n s : : a 、 m y n s : : c {\rm myns::a、myns::c} myns::amyns::c,此用法称为命名空间限定 ( q u a l i f i e d ) ({\rm qualified}) (qualified) m y n s : : a {\rm myns::a} myns::a称为被限定名 ( q u a l i f i e d n a m e ) ({\rm qualified\ name}) (qualified name)
  • 程序开发过程中,可以根据实际情况定义多个命名空间,把不同的库中的实体放到不同的命名空间中,即用不同的命名空间把不同的实体隐藏起来;

  • 对命名空间成员引用的语法格式:

    命名空间::命名空间成员名
    
  • 命名空间的几种使用方法:

    • 定义命名空间后,可以为其起一个别名:

      // 声明命名空间,名为:NameSpaceGraduateStudent;
      namespace NameSpaceGraduateStudent
      {...;
      }// 给命名空间起别名;
      namespace NSGS=NameSpaceGraduateStudent;
      
    • 使用 u s i n g {\rm using} using引入命名空间中的成员, u s i n g {\rm using} using的作用是引入命名空间或命名空间中的成员,其后面必须是由命名空间限定的名称;

      // 用using引入命名空间中的成员;
      // 引入后可以直接引用CStudent即可;
      using Stu::CStudent;// 等价关系;
      Stu::CStudent student ("Willard")	等价于		CStudent student ("Willard")
      
    • 使用 u s i n g n a m e s p a c e {\rm using\ namespace} using namespace引入命名空间,可以一次性引入命名空间的全部成员,语法格式:

      using namespace 命名空间名;
      
    • 无名的命名空间,在其他文件中无法使用,只能在本文件的作用域有效,语法格式:

      namespace
      {// 定义命名空间名;void func(){...;}
      }
      
  • 标准命名空间 s t d {\rm std} std,在程序中没有引入标准命名空间时,要使用其中的成员,则使用 s t d {\rm std} std来进行限定;

  • C {\rm C} C++头文件的作用:为用户提供调用其实现的外部接口;

10.5 实战

项目需求

约瑟夫 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)问题:假设有 n n n个小孩做成一个环,从第一个小孩开始数数,如果数到第 m m m个小孩,则该小孩离开,问最后留下的小孩是第几个小孩?

问题分析

如果总共有 6 6 6个小孩,围成一圈,从第一个小孩开始,每次数 2 2 2个小孩,则游戏情况过程:

小孩序号: 1 、 2 、 3 、 4 、 5 、 6 1、2、3、4、5、6 123456

离开小孩序号: 2 、 4 、 6 、 3 、 1 2、4、6、3、1 24631

则获胜小孩序号为: 5 5 5

代码实现 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)

  • J o s e p h u s R i n g . h {\rm JosephusRing.h} JosephusRing.h代码:

    /*** 作者:罗思维* 时间:2024/03/26* 描述:JosephusRing类定义头文件; */
    #pragma once
    #include <iostream>
    #include <iterator>			// iterator:迭代器 
    #include <list>				// list是一个容器,其结构为双向链表;using namespace std;template <class Type>
    class JosephusRing {list <Type> lst;public:class iterator;friend class iterator;class iterator: public std::iterator<std::bidirectional_iterator_tag, Type, ptrdiff_t> {typename list<Type>::iterator it;list<Type>* r;public:iterator(list<Type>& lst, const typename list<Type>::iterator& i): it(i), r(&lst) {};bool operator==(const iterator& x) const {return it == x.it;};bool operator!=(const iterator& x) const {return !(*this == x);};typename list<Type>::reference operator*() const {return *it;};iterator& operator++() {++it;if (it == r->end()) {it = r->begin();}return *this;};iterator operator++(int) {iterator tmp = *this;++* this;return tmp;};iterator& operator--() {if (it == r->begin()) {it = r->end();}--it;return *this;};iterator operator--(int) {iterator tmp = *this;--*this;return tmp;};iterator insert(const Type& x) {return iterator(*r, r->insert(it, x));};iterator erase() {return iterator(*r, r->erase(it));};};void push_back(const Type& x) {lst.push_back(x);};iterator begin() {return iterator(lst, lst.begin());};int size() {return lst.size();}
    };
    
  • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

    /*** 作者:罗思维* 时间:2024/03/26* 描述:程序主文件。 */
    #include "JosephusRing.h"int main() {int n, m;cout << "请输入小孩总数:";cin >> n;cout << "每次数的孩子数:";cin >> m;JosephusRing<int> Josephus;for (int i = 1; i <= n; i++) {Josephus.push_back(i);}JosephusRing<int>::iterator tmp = Josephus.begin();JosephusRing<int>::iterator it = tmp;for (int index = 0; index < n - 1; index++) {it = tmp;for (int j = 0; j < m - 1; j++) {it++;tmp++;}tmp++;cout << "离开的孩子:" << *it << endl;it.erase();}it = Josephus.begin();cout << "最后剩下的孩子:" << *it << endl;return 0;
    }
    

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

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

相关文章

API数据接口开发tglobal淘宝海外获得淘宝商品详情数据、商品ID、商品标题、价格、销量、规格属性等参数接入请求演示

要获取淘宝海外的商品详情、商品ID、商品标题、价格、销量、规格属性等参数&#xff0c;你可以使用淘宝海外的API。以下是一个简单的Python示例&#xff0c;使用requests库来调用淘宝海外的API。 首先&#xff0c;你需要注册一个开放平台账号并创建一个应用&#xff0c;以获取…

春秋云境CVE-2022-24663

简介 远程代码执行漏洞&#xff0c;任何订阅者都可以利用该漏洞发送带有“短代码”参数设置为 PHP Everywhere 的请求&#xff0c;并在站点上执行任意 PHP 代码。P.S. 存在常见用户名低权限用户弱口令 正文 进入首页我们没看到任何有价值的东西&#xff0c;那么就只好去寻找…

TOP100-回溯(二)

4.39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制…

【算法刷题 | 二叉树 05】3.28(左叶子之和、找树 左下角的值)

文章目录 11.左叶子之和11.1问题11.2解法一&#xff1a;递归11.2.1递归思路11.2.2代码实现 11.3解法二&#xff1a;栈11.3.1栈思想11.3.2代码实现 12.找树左下角的值12.1问题12.2解法一&#xff1a;层序遍历 11.左叶子之和 11.1问题 给定二叉树的根节点 root &#xff0c;返回…

【LeetCode】升级打怪之路 Day 28:回溯算法 — 括号生成 删除无效的括号

今日题目&#xff1a; 22. 括号生成301. 删除无效的括号 参考文章&#xff1a; 回溯算法&#xff1a;括号生成回溯算法&#xff1a;删除无效的括号 这是两道使用回溯算法来解决与括号相关的问题&#xff0c;具备一定的难度&#xff0c;需要学习理解。 通过第一道题“括号生成”…

RAFT:让大型语言模型更擅长特定领域的 RAG 任务

RAFT&#xff08;检索增强的微调&#xff09;代表了一种全新的训练大语言模型&#xff08;LLMs&#xff09;以提升其在检索增强生成&#xff08;RAG&#xff09;任务上表现的方法。“检索增强的微调”技术融合了检索增强生成和微调的优点&#xff0c;目标是更好地适应各个特定领…

查找总价格为目标值的两个商品【双指针】

这道题实际上跟本专栏上一题属于同一类型&#xff0c;是上一题的简单版&#xff0c;可以点击跳跃。 ⬇ 有效三角形的个数【双指针】 法一&#xff1a;暴力求解 class Solution { public:vector<int> twoSum(vector<int> &nums, int target){int n nums.size()…

Python3中画Sin (代码)

画正弦函数 import numpy as np import matplotlib.pyplot as plt # linspace() 函数用于生成等间隔的数字序列&#xff0c;接受三个参数&#xff1a;起始值&#xff0c;结束值&#xff0c;生成的点的数量 x np.linspace(0, 10, 100) y np.sin(x)plt.plot(x, y) plt.xlabel…

Vue中v-for多个Echarts图表组件只渲染一个要素问题排查

这个系列主要是用于记录我日常工作中遇到的一些Bug,既属于知识分享&#xff0c;也是对学习习惯的维持… 问题描述 今天&#xff0c;在开发一个WebGIS大屏项目时&#xff0c;我遇到了多个三维Echarts饼图图表渲染的问题&#xff0c;因为相似图表很多&#xff0c;我决定将Echart图…

Qt 多线程QThread的四种形式

重点&#xff1a; 1.互斥量&#xff1a;QMutex配套使用&#xff0c;lock(),unlock(),如果一个线程准备读取另一个线程数据时候采用tryLock()去锁定互斥量&#xff0c;保证数据完整性。 QMutexLocker简化版的QMutex,在范围区域内使用。 QMutex mutex QMutexLocker locker(&…

在Linux上使用nginx反向代理部署Docker网站

在政务云上部署Web环境&#xff0c;为了保证服务器安全&#xff0c;甲方只开放一个端口且只允许使用https协议进行访问&#xff0c;经过思考&#xff0c;决定使用docker部署网站&#xff0c;使用nginx反向代理&#xff0c;通过不同的二级域名访问不同的端口。 1 使用docker部署…

[Linux]条件变量:实现线程同步(什么是条件变量、为什么需要条件变量,怎么使用条件变量(接口)、例子,代码演示(生产者消费者模型))

目录 一、条件变量 1.什么是条件变量 故事说明 2、为什么需要使用条件变量 竞态条件 3.什么是同步 饥饿问题 二、条件变量的接口 1.pthread_cond_t 2.初始化&#xff08;pthread_cond_init&#xff09; 3.销毁&#xff08;pthread_cond_destroy&#xff09; 4.等待…

虚幻引擎资源加密方案解析

前段时间&#xff0c;全球游戏开发者大会(Game Developers Conference&#xff0c;简称GDC)在旧金山圆满落幕&#xff0c;会议提供了多份值得参考的数据报告。根据 GDC 调研数据&#xff0c;当下游戏市场中&#xff0c;Unreal Engine (下文简称虚幻)和 Unity 是使用最多的游戏引…

nginx代理解决跨域问题

文章目录 一、什么是跨域、跨域问题产生的原因二、注意事项三、nginx代理解决总结 一、什么是跨域、跨域问题产生的原因 跨域&#xff08;Cross-Origin&#xff09;是指在 Web 开发中&#xff0c;一个网页的运行脚本试图访问另一个网页的资源时&#xff0c;这两个网页的域名、…

蓝桥杯省三保底代码——数显+按键功能实现

目录 前言 一、为什么能保底省三 二、数显模块的实现 1.数码管显示​编辑 1&#xff09;断码表 2&#xff09;位选 3&#xff09;段选 4&#xff09;扫描 2.菜单 三、按键功能的实现 1.按键扫描 2.菜单切换 四、完整代码演示 五、结语 前言 上一期介绍全家桶时&…

【书生·浦语大模型实战营第二期】学习笔记1

1. Introduction 开源llm举例&#xff1a;LLaMA 、Qwen 、Mistral 和Deepseek 大型语言模型的发展包括预训练、监督微调&#xff08;SFT&#xff09;和基于人类反馈的强化学习&#xff08;RLHF&#xff09;等主要阶段 InternLM2的显著特点 采用分组查询注意力&#xff08;GQA…

IP组播基础

原理概述 IANA ( Internet Assigned Numbers Authority &#xff09;将 IP 地址分成了 A 、 B 、 C 、 D 、 E5类&#xff0c;其中的 D 类为组播 IP 地址&#xff0c;范围是224.0.0.0~239.255.255.255。 一个 IP 报文&#xff0c;其目的地址如果是单播 IP 地址&#xff…

螺旋矩阵的算法刷题

螺旋矩阵的算法刷题 本文主要涉及螺旋矩阵的算法 包括三个题目分别是 59. 螺旋矩阵 II54. 螺旋矩阵 中等LCR 146. 螺旋遍历二维数组 文章目录 螺旋矩阵的算法刷题一 、螺旋矩阵简单1.1 实现一&#xff08;我认为这个方法更巧妙&#xff01;&#xff01;&#xff09;1.2 实现二&…

短视频矩阵系统--技术3年源头迭代

短视频矩阵系统核心技术算法主要包括以下几个方面&#xff1a; 1. 视频剪辑&#xff1a;通过剪辑工具或API从各大短视频平台抓取符合要求的视频。这些视频通常符合某些特定条件&#xff0c;如特定关键词、特定时间段发布的视频、视频点赞评论转发等数据表现良好的视频。 2. 视…

2024年【熔化焊接与热切割】报名考试及熔化焊接与热切割模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割报名考试考前必练&#xff01;安全生产模拟考试一点通每个月更新熔化焊接与热切割模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过熔化焊接与热切割作业考试题库很简单。 1、【单选题】…