【C++】STL_ string的使用 + 模拟实现

news2025/1/11 12:52:22

前言

目录

    • 1. STL简介
      • (1)什么是STL
      • (2)STL的版本
      • (3)STL的六大组件
    • 2. string的使用
      • 2.1 npos
      • 2.2 遍历字符串string的每一个字符
      • 2.3 迭代器:
      • 2.4 string的内存管理
      • 2.5 string模拟实现
        • 2.5.1 深拷贝:
      • 3 .具体代码实现(string.hpp):
        • 3.1 拷贝构造代码实现:
        • 3.2 增删查改的代码实现:
        • 3.3 String中的成员变量和全局重载
        • 3.4 String中的运算符重载
        • 3.5 Windows上库里面对String的实现

1. STL简介

(1)什么是STL

STL是(standard template libaray-标准模板库)的首字母缩写,是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

(2)STL的版本

  • 原始版本:
    由HP实验室完成的原始版本,主要是给Visual studio使用。
  • P.J. 版本:
    由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。
  • RW版本:
  • SGR版本:
    由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。
    我们后面学习STL要阅读部分源代码,主要参考的就是这个SGR版本。

(3)STL的六大组件

  • 空间配置器–内存池
  • 迭代器
  • 配接器
  • 容器(其实是数据结构)
  • 仿函数
  • 算法
    在这里插入图片描述
    六大组件之间的关系:
    在这里插入图片描述
    迭代器 主要是用来访问容器的
    在这里插入图片描述
    Iterators特性:
  • 迭代器提供了通用的方法来访问容器。
  • iterator像指针一样的类型,有可能就是指针(比如vector、String),也有可能不是指针(比如Map、set、 list是类来封装List迭代器),其用法像指针一样的东西。
  • **iterator是个类型,**用这个类型可以定义一个对象

2. string的使用

String是类模板,string是被typedef 出来的,比STL产生的早,遵循STL的那一套.

  • 使用string的时候,要包含头文件 #include< string >
  • typedef basic_string string;
  • 由于string这个类中有上百个成员函数的接口,我们要会用其中比较常见的接口,string的学习文档:链接: 传送门
  • string是默认带\0 的,和C语言字符串一样。即:string s1;//只有一个\0

Operator at 和Operator [ ]的区别在于,Operator [ ]越界以后会抛异常。

2.1 npos

string 中的npos是静态成员变量,初始值是-1.
在这里插入图片描述

2.2 遍历字符串string的每一个字符

遍历字符串有三种方法:

  • 第一种方式,下标 + [] – []是C++重载的运算符。
  • 第二种方式,迭代器 – 迭代器是用来访问数据结构的。
  • 第三种方式,范围for – 前提是:C++11才支持的语法。
void test_string3()
{
	//遍历string的每一个字符
	string s1("hello");
	cout << s1[0] << endl;
	s1[0] = 'x';
	cout << s1.size() << endl;

	//遍历一共有三种方式

//·第一种方式,下标 + []  -- []是C++重载的运算符:

	//size就是返回它有多少个字符,是不包含\0的
	for (size_t i = 0; i < s1.size(); i++)
	{
		//s1.operator[](i);相当于调用这个函数
		cout << s1[i] << " ";//[]相当于函数调用
	}
	cout << endl;

	//编译器是看类型的,下面的运用和上面的类中调用成员函数完全不同
	//const char* s2 = "world";
	//s2[i];//*(s2 + i)

//·第二种方式,迭代器   --   迭代器是用来访问数据结构的:

	//sting::iterator是个类型,用这个类型可以定义一个对象

	string::iterator it = s1.begin();//或者叫iter
	//begin是指向第一个位置
	//end不是结束位置,而是最后一个位置的下一个位置
	//如果end是最后一个位置的下一个的话就会访问不到最后一个位置
	//[    ) -- 左闭右开的结构 -- 方便遍历

	//写成小于 < 也是可以的,但是不建议,标准的地方就是写的不等于 != 
	//统一用不等于 != 
	while (it != s1.end()) 
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//现阶段理解的迭代器:像指针一样的东西或者就是指针

//·第三种方式,范围for  --  前提是:C++11才支持的语法
    //范围for的原理:替换成迭代器
	//自动取元素,赋值给ch,自动判断结束,自动++
	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;
}

现阶段理解的迭代器:像指针一样的东西或者指针。
iterator是个类型,用这个类型可以定义一个对象

  • begin是指向第一个位置
  • end不是结束位置,而是最后一个数据的下一个位置
  • 如果end不是最后一个数据的下一个位置的话,循环条件中就会访问不到最后一个位置
  • [ ) – 左闭右开的结构 – 方便遍历

范围for:

  • 范围for又叫语法糖,因为它用起来很舒服很好用,省略了大量的代码
  • 其实在底层编译器替代成了迭代器,只是上层个看起来厉害
  • 大家可以通过看汇编代码来看底层实现的逻辑
  • 范围for和迭代器底层并没有太大差异

2.3 迭代器:

四种迭代器分类:

  • 第一种,普通的正向迭代器:const_iterator
  • 第二种,反向迭代器:reverse_iterator
  • 第三种,正向迭代器,能读不能写const_iterator
  • 第四种,反向迭代器,能读不能写const_reverse_iterator
//不改变就加const保护
//普通迭代器是可读可写的
void Func(const string& rs)
{
//第三种,正向迭代器,能读不能写
	string::const_iterator it = rs.begin();
	while (it != rs.end())
	{
		//(*it) += 1;
		cout << *it << " ";
		it++;
	}
	cout << endl;

//第四种,反向迭代器,能读不能写
	//string::const_reverse_iterator rit = rs.rbegin();
	//auto自动推导:
	auto rit = rs.rbegin();
	while (rit != rs.rend())
	{
		//(*rit) -= 1;
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
}

//四种迭代器:
void test_string5()
{
//第一种,普通的正向迭代器:
	string s("hello world");
	string::iterator it = s.begin();
	while (it != s.end())
	{
		(*it) += 1;
		cout << *it << " ";
		it++;
	}
	cout << endl;
	cout << s << endl;

//第二种,反向迭代器:
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		(*rit) -= 1;
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
	cout << s << endl;

	Func(s);

}
//iterator是终极方式,[] + 下标,是附带方式

2.4 string的内存管理

string的容量大小:Capacity
string的长度,既可以用length(),也可以用size();
reserve和resize都不会缩容量capacity,但是resize会让size降下来,只留size个。

Reserve只修改capacity大小,不修改size大小.
Resize既修改capacity大小,也修改size大小,会进行初始化
reserve和resize都不会缩容量capacity,但是resize会让size降下来,只留size个。

void test_string6()
{
	string s("hello world");
	//length产生的比size早
	cout << s.length() << endl;
	cout << s.size() << endl;
	cout << s.max_size() << endl;
	//容量要扩容
	cout << s.capacity() << endl;
}

2.5 string模拟实现

2.5.1 深拷贝:

浅拷贝的问题: 如果是栈的类,普通的浅拷贝(按字节拷贝),会出现问题,两个栈的str指针指向同一个地方,两个栈相互影响,我们并不希望这样,所以我们要学习一下深拷贝。

浅拷贝的效果:
在这里插入图片描述
深拷贝的效果:
在这里插入图片描述

3 .具体代码实现(string.hpp):

主要是增删查改拷贝构造

3.1 拷贝构造代码实现:
#pragma once

#include<iostream>
#include<assert.h>
#include<string>

using namespace std;

//class mystring
//class String

//自己实现的封装在命名空间中防止冲突
namespace Joker
{
	//实现一个简单的string,只考虑资源管理深浅拷贝的问题
	//暂且不考虑增删查改
	//string需要考虑完善的增删查改和使用的string
	class string
	{
	public:
		//const对象遍历访问是不可以被修改的,应该实现两种
		//两种迭代器的参数不同,函数重载
		typedef char* iterator;
		typedef const char* const_iterator;

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		//无参的构造函数
		/*string()
			:_size(0)
			,_capacity(0)
		{
			_str = new char[1];
			_str[0] = '\0';
		}*/

		//全缺省
		//1、"\0"这是有两个\0  
		//2、""这是有一个\0  
		//3、'\0'这里是**把\0的assic码值0**给了指针,实际是空指针**(注意:‘\0'的ascII为0 | ’0‘的ASCII值为48)**
		//而且如果支持c_str,cout的时候,解引用空指针会报错
		string(const char* str = "")     //""是C语言默认常量字符串,后面有\0
			:_size(strlen(str))          //strlen()是不会判空指针的
			, _capacity(_size)

		{
			_str = new char[_capacity + 1];//给'\0'多开一个
			strcpy(_str, str);
		}

//·构造函数:
//·传统的写法:本分,老实,老老实实干活,该开空间开空间,该拷贝数据就自己拷贝数据
		//s2(s1); - 深拷贝
		//在类里面只要用string对象访问成员都是不受限制的
		//私有是限制在类外面使用对象去访问成员
		/*string(const string& s)
			:_size(strlen(s._str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);
		}*/

//·现代写法:剥削,要完成深拷贝,自己不想干活,安排别人干活,然后窃取劳动成果
		//要初始化一下,不然有可能释放野指针
		string(const string& s)
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{
			string tmp(s._str);--调用构造函数
			swap(tmp);
		}

拷贝构造的现代写法:

  • 先构造函数一个string类型的 temp 对象:使用传过来指针实例化一个所需一样的对象
  • 再将tmp对象的内容和所要拷贝构造的对象的成员变量进行交换
  • 在将这个拷贝函数结束之后,tmp对象的生命周期结束,自动调用其析构函数,释放掉空间

注意:

和temp交换的this 代表的_str指针是随机值,交换给temp之后,析构对随机指针释放是会报错的。

//赋值重载:
//传统写法:
		//s1 = s3,如果不传引用返回,用传值返的话会深拷贝,代价太大了
		//new失败了之后会抛异常,用try捕获
		//string& operator = (const string& s)
		//{
		//	if (this != &s)
		//	{
		//		//1、先释放:如果s1开空间失败了,之前的空间也被释放了
		//			/*delete[] _str;
		//			_str = new char[strlen(s._str) + 1];
		//			strcpy(_str, s._str);*/

		//		//2、先开空间:下面写法可以避免上述问题
		//		char* tmp = new char[s._capacity + 1];
		//		strcpy(tmp, s._str);
		//		delete[] _str;
		//		_str = tmp;
		//		_size = s._size;
		//		_capacity = s._capacity;
		//	}
		//	return *this;
		//}

//现代写法:
//现代方法一:
		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				string tmp(s._str);--调用构造函数
				swap(tmp);
			}
			return *this;
		}*/

//现代方法二:-- 更简单,一行代码搞定,适用于所有深拷贝
		//s 就是 s1的深拷贝,先传参,传参就是拷贝构造
		string& operator=(string s) --调用拷贝构造
		{
			swap(s);
			return *this;
		}

赋值重载的现代写法:

  • 赋值函数中,形参是string类型的对象,调用函数是值传参
  • S对象已经是拷贝构造出来的对象,直接将s对象和所需要拷贝的对象交换就好。
~string()
{
	if (_str != nullptr)
	{
		delete[] _str;
		_str = nullptr;
		_size = _capacity = 0;
	}
}

const char* c_str() const
{
	return _str;
}

//普通对象调用这个
char& operator[](size_t pos)
{
	assert(pos < _size);
	return _str[pos];
}

//const修饰过的对象调用这个.(const引用中的const只是限定了不能通过此引用去修改变量的值)
const char& operator[](size_t pos) const
{
	assert(pos < _size);
	return _str[pos];
}

运算符[ ]的分析:

  • 如果是传值返回的话,要是想对其进行修改的话,就不行
  • 所以这里的话,必须是传的引用
3.2 增删查改的代码实现:
//s.size(&s)
//size_t size(cosnt string* const this)
size_t size() const
{
	return _size;
}
//加上const普通对象可以调用,const对象也可以调用
//不加的话const对象调用会有权限放大的风险

size_t capacity() const
{
	return _capacity;
}

//reserve扩容
void reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

//1、大于capacity
//2、小于capacity,大于size
//3、小于size
//resize的作用
//扩空间 + 初始化
//删除部分数据,保留前n个
		void resize(size_t n, char ch = '\0')
		{
			if (n < _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				if (n > _capacity)
				{
					reserve(n);
				}

				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

//复用push_back
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

//添加一个字符
		void push_back(char ch)
		{
			//if (_size == _capacity)
			//{
			//	reserve(_capacity == 0 ? 4 : _capacity * 2);
			//}

			//_str[_size] = ch;
			//_size++;
			//_str[_size] = '\0';
			insert(_size, ch);
		}

//复用append
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

//添加一个字符串
		void append(const char* str)
		{
			/*size_t len = _size + strlen(str);
			if (len > _capacity)
			{   
				reserve(len);
			}

			strcpy(_str + _size, str);
			_size = len;*/

			insert(_size, str);
		}
//Insert一个字符
	string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);

			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}  

			/*size_t end = _size;
			while (end >= pos)
			{
				_str[end + 1] = _str[end];
				end--;
			}*/

			//最好的一种方式
			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = ch;
			_size += 1;

			return *this;
		}

//Insert一个字符串
	string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (len == 0)
			{
				return *this;
			}
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}

			//往后挪动len个位置
			size_t end = _size + len;
			//while(end >= pos + len) //-- 最好别这样写,怕别人给极端场景,pos,end都是0
			while (end > pos + len - 1)
			{
				_str[end] = _str[end - len];
				end--;
			}
			strncpy(_str + pos, str, len);
			_size += len;

			return *this;
		}

//erase一个数值
string& erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				size_t begin = pos + len;
				while (begin <= _size)
				{
					_str[begin - len] = _str[begin];
					begin++;
				}

				_size -= len;
			}
			return *this;
		}
//求字串的函数
string substr(size_t pos,size_t len=npos)const
{
   assert(pos<_size);
   size_t reallen=len;
   if(len==npos||pos+len >_size)
   {
      reallen=_size-pos;
   }
   string sub;
   for(size_t i=0;i<reallen;++i)
   {  
      sub+=_str[pos+i];
   }
   return sub;
}

size_t find(char ch, size_t pos = 0)
		{
			for (; pos < _size; pos++)
			{
				if (_str[pos] == ch)
				{
					return pos;
				}
			}
			return npos;
		}

size_t find(const char* str, size_t pos = 0)
		{
			const char* p = strstr(_str + pos, str);
			//KMP,BM只做了解

			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _str;
			}
		}

全局Swap函数和 string::Swap( )成员函数的区别:

  • 上述逻辑和之前C语言实现的逻辑并无二异
  • 只是用了C++的语法
//交换 -- 用库里的交换还要调用拷贝构造
void swap(string& s)
{
	//调用库里的 -- 库中的(类模板)是全局的,也可以写std
	::swap(_str, s._str);
	::swap(_size, s._size);
	::swap(_capacity, s._capacity);
}
3.3 String中的成员变量和全局重载
private:
	char* _str;
	size_t _size;		//有效字符个数 -- 不包含'\0'
	size_t _capacity;	//存储有效字符的空间

	//静态不能给缺省值,强制要求在类外面定义
	const static size_t npos;
};

//定义
const size_t string::npos = -1;

//流插入
ostream& operator<<(ostream& out, const string& s)
{
	//中间有'\0'就不能将整个字符串打印完
	//out << s.c_str() << endl;
	
	//趋向于这样写 -- 这样能保证每个字符都能打印出来
	for (auto ch : s)
	{
		out << ch;
	}

	return out;
}

//流提取
	istream& operator>>(istream& in, string& s)
	{
		//方法一:
		//char ch;
		//in >> ch;
		//ch = in.get();
		//while (ch != ' ' && ch != '\n')
		//{
		//	s += ch;
		//	//in >> ch;
		//	ch = in.get();
		//}

		//要清理掉之前的空间
		s.clear();
		char ch;
		ch = in.get();
		char buff[128] = { '\0' };
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				s += buff;
				memset(buff, 0, sizeof(char) * 128);
				i = 0;
			}
			ch = in.get();
		}

		s += buff;
		return in;
	}


void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
3.4 String中的运算符重载

运算符重载不一定是成员函数,可以写成全局

	bool operator<(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) < 0;
	}

	bool operator==(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}

	bool operator<=(const string& s1, const string& s2)
	{
		return s1 < s2 || s1 == s2;
	}

	bool operator>(const string& s1, const string& s2)
	{
		return !(s1 <= s2);
	}

	bool operator>=(const string& s1, const string& s2)
	{
		return !(s1 < s2);
	}

	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}
}
3.5 Windows上库里面对String的实现

总共有28个字节,成员变量如下:

private//好处就是对小字符操作更快,以空间换时间
		//<16 字符串存在buff数组中
		//>=16 存在_str指向的堆空间上
		  char   _buff[16];
          size_t _capacity;
		  size_t _size;
		  char* _str;

尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

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

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

相关文章

MySQL学习笔记10——日志

日志 一、日志1、通用查询日志&#xff08;1&#xff09;开启通用查询日志&#xff08;2&#xff09;查看通用查询日志&#xff08;3&#xff09;删除通用查询日志 2、慢查询日志3、错误日志4、二进制日志&#xff08;1&#xff09;查看二进制日志&#xff08;2&#xff09;刷新…

创新指南|创新组合管理的7个陷阱以及如何避免它们

进入未知领域的第一步可能具有挑战性。尽管创新会犯错误&#xff0c;但在将 IPM 作为公司实践实施时&#xff0c;您可以准备好并避免一些常见的陷阱。在这篇文章中&#xff0c;我们将讨论组织在实施创新组合管理时遇到的最常见的陷阱。 01. 在映射中包含日常业务任务 映射中的…

工会排队返现:创新促销模式,实现消费者与商家双赢

在数字化营销日益盛行的今天&#xff0c;各种促销策略层出不穷&#xff0c;但真正能够打动消费者内心并促成双赢局面的策略却并不多见。工会排队返现模式便是其中一例&#xff0c;它巧妙地融合了积分奖励、奖金池累积以及排队等待机制&#xff0c;为消费者和商家带来了全新的互…

C++入门--引用

点赞关注不迷路&#xff01;本节涉及C入门--引用 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1f44d;&#x1f3fb; 收藏 ✨ 加关注&#x1f440; 期待与你共同进步! 1.1 引用的概念 啥叫引用&#xff1f;其实很好理解&#xff0c;比如你隔壁邻居的孩子上学时大…

【练习3】

1.将二叉搜索树转为排序的双向链表 (好久没看数据结构&#xff0c;忘完了&#xff0c;学习大佬的代码&#xff09; class Solution { public:Node* prenullptr,*headnullptr; //pre为每次遍历时的前一个节点&#xff0c;head记录头节点Node* treeToDoublyList(Node* root) {if…

PHP单独项目启动演示

文章目录 phpstudy得到文件打开phpStudy.exe运行项目 phpstudy 得到文件 一般我们会得到这么一个项目文件&#xff0c;如果外层有“中文路径”&#xff0c;请剪切此内容作为项目根目录即可 打开phpStudy.exe 因为我又正常的编程环境和mysql&#xff0c;所以这里是正常的&a…

linux数据备份与恢复

目录 前言 1、数据备份和恢复中的两个关键性指标 2、linux系统的定时任务 1&#xff09;本地定时任务crontab 在实验测试过程中&#xff0c;遇到多次crontab任务不执行问题 &#xff0c;总结下来主要有几个方面原因&#xff1a; 2)分布式定时任务系统Jenkins 3、备份存储…

TinyEngine 低代码引擎区块局域网部署方案全新上线!

本文由体验技术团队 TinyEngine 项目组成员创作~ 在 TinyEngine 开源后&#xff0c;对私有化部署存在诉求的用户越来越多&#xff0c;而当前 TinyEngine 多项内容都依托在公网中&#xff0c;当前官网提供的区块发布方案&#xff0c;为公网环境下的发布&#xff0c;不能完全满足…

信创基础软件之数据库

一、数据库概述 数据库是一种用于存储和管理拥有固定格式和结构数据的仓库型数据管理系统。其主要用于业务数据的存储和业务逻辑运算&#xff0c;具体负责保障数据的安全性、完整性、多用户对数据的并发使用以及发生故障后的系统恢复。 二、数据库的体系架构 数据库内核:对数…

C语言 函数的嵌套与递归 调用

本文 我们来说函数的嵌套调用和递归调用 在很多大型项目中 我们肯定不可能将所有逻辑都写在一个函数中 肯定要按功能拆解成多个特定的功能函数 函数并不允许嵌套调用&#xff0c;但是 允许在逻辑代码中嵌套调用 所谓函数嵌套调用 就是在一个函数中调用另一个函数&#xff0c;而…

VS编辑器下使用MFC完成研究生管理系统设计

背景&#xff1a; &#xff08;一&#xff09;实验目的 通过该实验&#xff0c;使学生掌握windows程序设计的基本方法。掌握学籍管理的基本内容&#xff0c;熟练应用数据库技术和通用组件&#xff0c;实现研究生信息的增、删、改、查功能。通过处理过程对计算机软件系统工作原…

【Linux进程间通信(六)】深入理解 System V IPC

&#xff08;一&#xff09;引入 &#xff08;二&#xff09;IPC 命名空间 &#xff08;三&#xff09;ipc_ips结构体 &#xff08;四&#xff09;ipc_id_ary结构体 &#xff08;五&#xff09;kern_ipc_perm结构体 &#xff08;六&#xff09;操作系统对IPC资源是如何管理…

mybatis:Spring junit 测试报错:Failed to load ApplicationContext

Spring junit 测试报错&#xff1a;Failed to load ApplicationContext 解决方法&#xff0c;修改mybatis版本&#xff0c;版本过高导致无法加载依赖

NVIDIA Omniverse Cloud API支持数字孪生开发,可解决复杂AI问题 | 最新快讯

在全球范围内&#xff0c;价值超过 50 万亿美元的重工业市场&#xff0c;正在竞相实现数字化。 基于此&#xff0c;为帮助数字孪生技术更好地赋能千行百业&#xff0c;AI 企业 NVIDIA 在架构底层算力的同时&#xff0c;也搭建了 NVIDIA AI Enterprise 和 Omniverse 两大平台。 …

PDF转word转ppt软件

下载地址&#xff1a;PDF转word转ppt软件.zip 平时工作生活经常要用到PDF转word转ppt软件&#xff0c;电脑自带的又要开会员啥的很麻烦&#xff0c;现在分享这款软件直接激活就可以免费使用了&#xff0c;超级好用&#xff0c;喜欢的可以下载

【不使用深度学习框架】多层感知机实现手写Minist数据集识别

手写Minist识别是一个非常经典的问题&#xff0c;其数据集共有70000张28*28像素的图片&#xff0c;其中60000张作为训练集&#xff0c;剩下的10000张作为测试集&#xff0c;每一张图片都表示了一个手写数字&#xff0c;经过了灰度处理。 本文延续前面文章提到的多层感知机&…

五一 Llama 3 超级课堂 大完结

首先很感谢上海人工智能实验室和机智流等相关举办单位组织的这个活动&#xff0c;在Llama3发布不多时就让我们可以体验到大模型的进步&#xff0c;回顾整个活动&#xff0c;从内容上看是相当用心的。从A100的提供使用到大模型部署&#xff0c;微调&#xff0c;Agent功能应用和数…

网贷大数据查询要怎么保证准确性?

相信现在不少人都听说过什么是网贷大数据&#xff0c;但还有很多人都会将它跟征信混为一谈&#xff0c;其实两者有本质上的区别&#xff0c;那网贷大数据查询要怎么保证准确性呢?本文将为大家总结几点&#xff0c;感兴趣的朋友不妨去看看。 想要保证网贷大数据查询的准确度&am…

Mamba结构的Demo源码解读

文章目录 前言一、mamba结构构建辅助函数解读1、dataclass方法解读2、Norm归一化LayerNormRMSNormRMSNorm源码 3、nn.Parameter方法解读 二、mamba原理二、mamba模型构建1、主函数入口源码解读2、Mamba类源码解读 三、ResidualBlock的mamba结构源码解读四、MambaBlock构成Resid…

【四、性能测试】性能测试基础与几个重要的概念

你好&#xff0c;我是山茶&#xff0c;一个95后在职程序员。也是一个目标跟 1000 程序员探索出 AI 测试 副业之路的 bro&#xff0c;欢迎跟我一起沟通交流&#xff01; 一、什么是性能测试&#xff1f; 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来…