【C++】string类模拟实现

目录

💕1.模拟string类构造函数

💕2.模拟构造函数实现

💕3.拷贝构造函数模拟实现 

💕4.析构函数模拟实现 

💕5.size函数,capacity函数模拟实现 

💕6.begin函数,end函数,模拟实现 

💕7.=赋值运算符重载模拟实现

💕8.访问运算符重载 模拟实现

💕9.reserve函数模拟实现 

💕10.push_back函数模拟实现

💕11.append函数模拟实现

💕 12.+=运算符重载

💕13.find函数模拟实现 

💕14.insert函数指定位置插入字符模拟实现

💕15.insert函数指定位置插入字符串模拟实现

💕16.erase函数模拟实习 

💕17.判断运算符重载

💕18.输出/输入运算符重载

💕19.clear函数 

💕20.总体代码

💕21.完结 


(最新更新时间——2025.1.23——各位小年快乐) 

不过是卑贱的下人 杀了就杀了 

💕1.模拟string类构造函数

我们知道string在C++中是一个单独的名,如果我们想要模拟string类的实现,我们就需要使用命名空间域将string重命名

那么在.h文件中我们可以这样写


blogstring.h的初始模板

#pragma once
#include<iostream>
include<assert.h>
using namespace std;
namespace blog
{class string{private:char* _str;//字符串首地址size_t _size;//有效个数size_t _capacity;//容量};
}

将string的初始成员变量安置后,我们先进行构造函数的实现


💕2.模拟构造函数实现

 构造函数分为有参构造函数,无参构造函数,以及拷贝构造函数,因此,有参构造函数和无参构造函数可以使用全缺省,合并为一个构造函数,拷贝构造函数单独进行实现


首先思考,我们有参构造函数与无参构造函数的形参是字符串,因此,我们的形参应当也是const char* str,const char* str的意义就是字符串类型

再次思考,既然要实现构造函数,那就要对成员变量进行更改,有效个数可以使用strlen函数,容量的话可以先使用size的数值,_str可以使用size的数值进行开辟空间

但需要注意的是capacity开辟出来的容量应该要多一个,多出来的是'\0'的位置


因此,我们可以这样写->:

string.cpp的构造函数

#define _CRT_SECURE_NO_WARNINGS 
#include"blogstring.h"
namespace blog
{string::string(const char* str):_size(strlen(str)){_capacity = _size;//更新容量_str = new char[_capacity+1];//开辟capacity+1个char类型的空间,因为有一个是'\0'的strcpy(_str, str);//strcpy(char* 目标字符串,char* 源字符串)函数,传入两个地址,将源字符串的内容复制到目标字符串中}
}

注意我们的string.c文件中,使用的是命名空间域,这样是因为我们的成员变量是私有的,而不同文件的命名空间域会合并在一起,因此,我们在实现string.c文件时,可以直接让形参访问成员变量


同时我们的全缺省需要写到头文件中,如果我们什么都没传该怎么写,传空字符串,size应该是0。如何让size是0?

我们只需要在头文件处更新一下缺省值即可,如下->:

blogstring.h更新

namespace blog
{class string{public:string(const char* str = "");//有参&&无参构造函数private:char* _str;//字符串首地址size_t _size;//有效个数size_t _capacity;//容量};
}

💕3.拷贝构造函数模拟实现 

如何实现拷贝构造函数,我们回想一下如何使用,string s2(s1),我们的形参应该是一个字符串类型的,那么,我们的头文件可以这样写->:


blogstring.h

#pragma once
#include<iostream>
using namespace std;
namespace blog
{class string{string(const char* str = "");//有参&&无参构造函数string(const string& str);//拷贝构造函数private:char* _str;//字符串首地址size_t _size;//有效个数size_t _capacity;//容量};
}

思考一下,拷贝构造函数的实现应该实现深拷贝,也就是需要开辟新的空间,那么既然要开辟新的空间,我们就需要知道形参字符串的有效之,因此我们可以这样写->:

这里只写拷贝构造函数的实现了,往后也是如此

	string::string(const string& str){_str = new char[str._capacity+1];//开辟新的空间_size = str._size;_capacity = str._capacity;strcpy(_str, str._str);}

如此,就显示出我们之前使用命名空间域合并的优势了

💕4.析构函数模拟实现 

想要实现析构函数,我们就要释放内存并进行空指针化,这点很简单,代码如下->:


string.h

~string();//析构函数

string.c

	string:: ~string(){_size = _capacity = 0;delete[] _str;_str = nullptr;}

💕5.size函数,capacity函数模拟实现 

实现size函数与capacity函数的实现,就是实现返回字符串的size和capacity是多少,这一点也简单容易实现,如下->:

string.h

size_t size();//返回_size
size_t capacity();//返回_capacity

string.c

	//返回_sizesize_t string::size(){return _size;}//返回_capacitysize_t string::capacity(){return _capacity;}

💕6.begin函数,end函数,模拟实现 

在我们模拟实现时,迭代器的类型iterator不可以直接使用,我们需要使用typedef将其重命名一下才可以使用,那么我们的头文件需要先整体更新一下->:


string.h

#pragma once
#include<iostream>
using namespace std;
namespace blog
{class string{typedef char* iterator ;typedef const char* const_iterator;public:string(const char* str = "");//有参&&无参构造函数string(const string& str);//拷贝构造函数~string();//析构函数size_t size();//返回_sizesize_t capacity();//返回_capacityiterator begin();//begin函数iterator end();//end函数const_iterator begin() const;//const begin函数const_iterator end() const;//const end函数private:char* _str;//字符串首地址size_t _size;//有效个数size_t _capacity;//容量};
}

因为原本的begin与end函数有const与非const类型,所以我们这里也模仿上


begin函数返回的是字符串首地址,end函数返回的是'\0'的位置,那么就很好实现了


string.cpp

//begin函数
string::iterator string::begin()
{return _str;
}//end函数
string::iterator string::end()
{return _str+_size;
}//const begin函数
string::const_iterator string::begin()const
{return _str;
}//const end函数
string::const_iterator string::end()const
{return _str + _size;
}

💕7.=赋值运算符重载模拟实现

想要实现赋值运算符,首先想想它可以怎样用,它可以,string s1 = s2这样用,也可以s2 = s3

这样用,这就说明我们传过去的形参,可能已经被初始化了,也可能没有被初始化,这就会导致capacity可能不够的问题,因此,需要先判断一下,再进行深拷贝


如果像string s1 = s2还容易弄,毕竟就像拷贝构造函数一样,但如果是s2 = s3呢?我们需要更改s2的capacity,那么,可以这样写->:


string.h

string& operator=(const string& s);//赋值运算符重载

string.cpp

	//赋值运算符重载string& string::operator=(const string& s){_capacity = s._capacity;//更改capacity_size = s._size;//更改_sizechar* tep = new char[_capacity+1];//开辟一样的空间strcpy(tep, s._str);//将内容复制过去delete[] _str;_str = tep;return *this;}

我们对于.cpp文件也可以进行更一步的优化,如果两个对象不相等的话,进行更改,否则直接返回,如下->:

	//赋值运算符重载string& string::operator=(const string& s){//这里是取地址操作符if (this != &s) {_capacity = s._capacity;//更改capacity_size = s._size;//更改_sizechar* tep = new char[_capacity+1];//开辟一样的空间strcpy(tep, s._str);//将内容复制过去delete[] _str;_str = tep;}return *this;}

💕8.访问运算符重载 模拟实现

想要实现访问运算符,我们想想arr[1],返回的是一个确切的值,那么这里返回的就应该是char类型的,避免内存重复开辟我们可以使用char&来作为返回值(堆区开辟的内存,不会主动释放)


string.h

string类中有const与非const,我们也这样实现

char& operator[](size_t pos);//访问运算符重载
const char& operator[](size_t pos) const;//const 访问运算符重载

string.cpp

	//访问运算符重载char& string::operator[](size_t pos){assert(pos >= 0 && pos < _size);return *(_str + pos);}//const 访问运算符重载const char& string::operator[](size_t pos) const{assert(pos >= 0 && pos < _size);return *(_str + pos);}

💕9.reserve函数模拟实现 

 reserve函数是用来预留空间的,而且只可以扩不可以缩,这一点我们之前有讲,所以只需要重新开一段空间并将值拷贝过去即可


string.h

void reserve(size_t n);//预留空间

string.cpp

	//预留空间模拟实现void string::reserve(size_t n){if (n > _capacity){_capacity = n;char* tep = new char[_capacity + 1];strcpy(tep, _str);delete[] _str;_str = tep;}}

💕10.push_back函数模拟实现

想要实现push_bakc进行尾插,首先需要判断的就是是否需要扩容,以及是否是空容量的问题,之后就是插入的问题,不要忘记'\0'的处理


string.h

void push_back(char ch);//尾插一个字符

string.cpp

	//尾插字符void string::push_back(char ch){//判断是否需要扩容if (_size == _capacity) {size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';++_size; }

💕11.append函数模拟实现

attend函数是尾插字符串,依旧需要先判断是否扩容,接着我们可以使用一个c语言中学习的string类型的函数进行尾插


string.h

void append(const char* str);//尾插一个字符串

string.cpp

	//尾插字符串void string::append(const char* str){	size_t len = strlen(str);//计算字符串多长,方便修改size//判断是否需要扩容if (_size == _capacity) {size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}strcpy(_str + _size, str);_size += len;}

💕 12.+=运算符重载

 +=运算符重载可以既尾插一个字符,也可以尾插一个字符串,是两种类型,这里非常容易实现,直接套现push_back和append函数即可,代码如下->:


string.h

string& operator+=(char ch);//+=运算符重载,尾插字符
string& operator+=(const char* str);//+=运算符重载,尾插字符串

string.cpp

	//+=运算符重载,尾插字符string& string::operator+=(char ch){push_back(ch);return *this;}//+=运算符重载,尾插字符串string& string::operator+=(const char* str){append(str);return *this;}

💕13.find函数模拟实现 

find函数的实现也很简单,代码如下->:


string.h

size_t find(char ch, size_t pos = npos);//查找某个字符
size_t find(const char* str, size_t pos = npos);//查找某个字符串
static const size_t npos;//我们需要定义静态npos设为找不到的情况

查找某个字符串时可以直接用函数来实现,并通过指针-指针返回中间元素的个数,进而直接反馈出下标是多少

string.cpp

const size_t string::npos = -1;//查找某个字符size_t string::find(char ch, size_t pos){
//方法一:/*while (_str + pos < _str + _size){if (*(_str + pos) == ch){return (_str + pos) - _str;}pos++;}return npos;*///方法二:for (size_t i = pos; i < _size; i++){if (*(_str + i) == ch){return i;}}return npos;}//查找某个字符串size_t string::find(const char* str, size_t pos){if (p == nullptr)return npos;char* p = strstr(_str + pos, str);return  p - _str;}

💕14.insert函数指定位置插入字符模拟实现

insert函数的模拟实现,其实就像数据结构实现顺序表的样子

 先讲插入位置后面的数据全部后移,再进行擦插入。需要先判断是否需要扩容,因为有可能直接使用insert插入,导致capacity是0


string.h

void insert(size_t pos, char ch);//指定位置插入字符

string.cpp

//指定位置插入字符
void string::insert(size_t pos, char ch)
{assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;
}

💕15.insert函数指定位置插入字符串模拟实现

插入字符串是类似的,只不过用到了memcpy函数进行了将字符串复制上去


string.h

void insert(size_t pos, const char* str);//指定位置插入字符串

string.cpp

//指定插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len);_size += len;}

💕16.erase函数模拟实习 

指定位置删除字符需要注意的是删去的长度,大于字符串就全删。

删去后使用strcpy进行覆盖,并进行size的减去


string.h

void erase(size_t pos = 0, size_t len = npos);//指定位置删除字符串

string.cpp

	void string::erase(size_t pos , size_t len ) {assert(pos < _size);// len大于前面字符个数时,有多少删多少if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);//用strcpy进行覆盖_size -= len;}}

 

💕17.判断运算符重载

这里很简单,不进行解释了


string.h
 

bool operator<(const string& s) const;
bool operator>(const string& s) const;
bool operator<=(const string& s) const;
bool operator>=(const string& s) const;
bool operator==(const string& s) const;
bool operator!=(const string& s) const;

string.cpp

bool string::operator<(const string& s) const
{return strcmp(_str, s._str) < 0;
}bool string::operator>(const string& s) const
{return !(*this <= s);
}bool string::operator<=(const string& s) const
{return *this < s || *this == s;
}bool string::operator>=(const string& s) const
{return !(*this < s);
}bool string::operator==(const string& s) const
{return strcmp(_str, s._str) == 0;
}bool string::operator!=(const string& s) const
{return !(*this == s);
}

💕18.输出/输入运算符重载

输出输入运算符的重载是要在类外写的,但是不要出了命名空间域,否则会无法访问成员变量(不使用友元)


string.h

istream& operator>> (istream& is, string& str);
ostream& operator<< (ostream& os, const string& str);

string.cpp

istream& operator>> (istream& is, string& str)
{str.clear();//下面讲char ch = is.get();while (ch != ' ' && ch != '\n'){str += ch;ch = is.get();}return is;
}ostream& operator<< (ostream& os, string& str)
{for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;
}

💕19.clear函数 

我们在cout重载时,如果不将对象清理,那就会变成尾插,因此,我们需要先进行初始化清理一下


clear函数把字符串首字符设为字符串结束符 '\0',这意味着字符串内容为空。同时将字符串的大小 _size 置为 0


string.h

void clear();//清理函数

string.cpp

	void string::clear(){_str[0] = '\0';_size = 0;}

💕20.总体代码

 string.h

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace blog
{class string{typedef char* iterator ;typedef const char* const_iterator;public://test1string(const char* str = "");//有参&&无参构造函数string(const string& str);//拷贝构造函数~string();//析构函数size_t size() const;//返回_sizesize_t capacity();//返回_capacity//test2iterator begin();//begin函数iterator end();//end函数const_iterator begin() const;//const begin函数const_iterator end() const;//const end函数//test3string& operator=(const string& s);//赋值运算符重载char& operator[](size_t pos);//访问运算符重载const char& operator[](size_t pos) const;//const 访问运算符重载//test4void reserve(size_t n);//预留空间void push_back(char ch);//尾插一个字符void append(const char* str) ;//尾插一个字符串string& operator+=(char ch);//+=运算符重载,尾插字符string& operator+=(const char* str);//+=运算符重载,尾插字符串//test5size_t find(char ch, size_t pos = 0);//查找某个字符size_t find(const char* str, size_t pos = 0);//查找某个字符串//test6void insert(size_t pos, char ch);//指定位置插入字符void insert(size_t pos, const char* str);//指定位置插入字符串void erase(size_t pos = 0, size_t len = npos);//指定位置删除字符串bool operator<(const string& s) const;bool operator>(const string& s) const;bool operator<=(const string& s) const;bool operator>=(const string& s) const;bool operator==(const string& s) const;bool operator!=(const string& s) const;void clear();//清理函数private:char* _str;//字符串首地址size_t _size;//有效个数size_t _capacity;//容量static const size_t npos;};istream& operator>> (istream& is, string& str);//重载输入ostream& operator<< (ostream& os, string& str);//重载输出
}

string.cpp

#define _CRT_SECURE_NO_WARNINGS 
#include"blogstring.h"
namespace blog
{const size_t string::npos = -1;//构造函数string::string(const char* str):_size(strlen(str)){_capacity = _size;//更新容量_str = new char[_capacity + 1];//开辟size个char类型的空间strcpy(_str, str);//strcpy(char* 目标字符串,char* 源字符串)函数,传入两个地址,将源字符串的内容复制到目标字符串中}//拷贝构造函数string::string(const string& str){_str = new char[str._capacity + 1];//开辟新的空间_size = str._size;_capacity = str._capacity;strcpy(_str, str._str);}//析构函数string:: ~string(){_size = _capacity = 0;delete[] _str;_str = nullptr;}//返回_sizesize_t string::size() const{return _size;}//返回_capacitysize_t string::capacity(){return _capacity;}//begin函数string::iterator string::begin(){return _str;}//end函数string::iterator string::end(){return _str + _size;}//const begin函数string::const_iterator string::begin()const{return _str;}//const end函数string::const_iterator string::end()const{return _str + _size;}//赋值运算符重载string& string::operator=(const string& s){//这里是取地址操作符if (this != &s) {_capacity = s._capacity;//更改capacity_size = s._size;//更改_sizechar* tep = new char[_capacity + 1];//开辟一样的空间strcpy(tep, s._str);//将内容复制过去delete[] _str;_str = tep;}return *this;}//访问运算符重载char& string::operator[](size_t pos){assert(pos >= 0 && pos < _size);return *(_str + pos);}//const 访问运算符重载const char& string::operator[](size_t pos) const{assert(pos >= 0 && pos < _size);return *(_str + pos);}//预留空间模拟实现void string::reserve(size_t n){if (n > _capacity){_capacity = n;char* tep = new char[_capacity + 1];strcpy(tep, _str);delete[] _str;_str = tep;}}//尾插字符void string::push_back(char ch){//判断是否需要扩容if (_size == _capacity) {size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';++_size;}//尾插字符串void string::append(const char* str){size_t len = strlen(str);//计算字符串多长,方便修改size//判断是否需要扩容if (_size == _capacity) {size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}strcpy(_str + _size, str);_size += len;}//+=运算符重载,尾插字符string& string::operator+=(char ch){push_back(ch);return *this;}//+=运算符重载,尾插字符串string& string::operator+=(const char* str){append(str);return *this;}//查找某个字符size_t string::find(char ch, size_t pos){for (size_t i = pos; i < _size; i++){if (*(_str + i) == ch){return i;}}return npos;}//查找某个字符串size_t string::find(const char* str, size_t pos){char* p = strstr(_str + pos, str);if (p == nullptr)return npos;return  p - _str;}//指定位置插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}//指定插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}size_t end = _size;while (end > pos){_str[end + len] = _str[end];--end;}memcpy(_str + pos, str, len);_size += len;}//指定位置删除void string::erase(size_t pos, size_t len){assert(pos < _size);// len 大于剩余字符个数时,有多少删多少if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{// 使用 memmove 避免内存重叠问题memmove(_str + pos, _str + pos + len, _size - pos - len + 1);_size -= len;}}bool string::operator<(const string& s) const{return strcmp(_str, s._str) < 0;}bool string::operator>(const string& s) const{return !(*this <= s);}bool string::operator<=(const string& s) const{return *this < s || *this == s;}bool string::operator>=(const string& s) const{return !(*this < s);}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s) const{return !(*this == s);}//清理函数void string::clear(){_str[0] = '\0';_size = 0;}//输入重载istream& operator>> (istream& is, string& str){str.clear();char ch = is.get();while (ch != ' ' && ch != '\n'){str += ch;ch = is.get();}return is;}//输出重载ostream& operator<< (ostream& os,string& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}
}

test.cpp


这里包含了测试用例

#define _CRT_SECURE_NO_WARNINGS 
#include"blogstring.h"
void test1()
{blog::string s1("hello world");//测试构造函数cout << s1<<endl;blog::string s2(s1);//测试拷贝构造函数cout << s2 << endl;blog::string s3(s2);s1.~string();//测试析构函数cout << s1.capacity()<<' ' << s1.size() << endl;//测试size与capacity函数
}void test2()
{blog::string s1("hello world");printf("%p\n", s1.begin());//测试beginprintf("%p\n", s1.end());//测试endconst blog::string s2(s1);printf("%p\n", s2.begin());//测试beginprintf("%p\n", s2.end());//测试end
}void test3()
{blog::string s1("hello world");s1 = "ming ri fang zhou";//测试赋值运算符重载cout << s1 << endl;for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << ' ';//测试[]运算符重载}cout << endl;const blog::string s2("nihao");for (size_t i = 0; i < s2.size(); i++){cout << s2[i] << ' ';//测试[]运算符重载}
}void test4()
{blog::string s1("hello world");cout << s1.capacity() << endl;s1.reserve(200);//测试reservecout << s1.capacity() << endl;s1.push_back('x');//测试push_backs1.append("oppo");//测试appends1 += 'p';//测试+=运算符重载s1 += "lll";//测试+=运算符重载cout << s1 << endl;}void test5()
{blog::string s1("hello world");int tep1 = s1.find('l');int tep2 = s1.find("or");cout << tep1<<' '<<tep2<<endl;
}void test6()
{blog::string s1;s1.insert(0, 'x');cout << s1 << endl;s1.insert(1, "xxxx");cout << s1 << endl;s1.erase(1);cout << s1 << endl;
}
int main()
{//test1();//test2();//test3();//test4();//test5();//test6();
}

💕21.完结 

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

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

相关文章

微调Qwen2:7B模型,加入未知信息语料

对于QWen2这样的模型,在微调的时候,语料的投喂格式满足ChatML这样的格式!!! OpenAI - ChatML: 下面是ChatML格式的介绍: https://github.com/openai/openai-python/blob/release-v0.28.0/chatml.mdhttps://github.com/openai/openai-python/blob/release-v0.28.0/chat…

.Net Core微服务入门全纪录(四)——Ocelot-API网关(上)

系列文章目录 1、.Net Core微服务入门系列&#xff08;一&#xff09;——项目搭建 2、.Net Core微服务入门全纪录&#xff08;二&#xff09;——Consul-服务注册与发现&#xff08;上&#xff09; 3、.Net Core微服务入门全纪录&#xff08;三&#xff09;——Consul-服务注…

HTML根元素<html>的语言属性lang:<html lang=“en“>

诸神缄默不语-个人CSDN博文目录 在编写HTML页面时&#xff0c;通常会看到<html lang"en">这行代码&#xff0c;特别是在网页的开头部分&#xff0c;就在<!DOCTYPE html>后面。许多开发者可能对这个属性的含义不太了解&#xff0c;它到底有什么作用&…

小样本学习中的Prototypical Network(原型网络)详解

Few-shot Learning ,即“小样本学习”,是一种机器学习方法,旨在通过极少量样本训练模型,使其能够快速适应新任务或新类别。这种方法在数据稀缺的场景中非常有用。 Prototypical Network(原型网络)是小样本学习中的经典方法之一,特别适用于分类任务。它的核心思想是通过学…

mock可视化生成前端代码

介绍&#xff1a;mock是我们前后端分离的必要一环、ts、axios编写起来也很麻烦。我们就可以使用以下插件&#xff0c;来解决我们的问题。目前支持vite和webpack。&#xff08;配置超级简单&#xff01;&#xff09; 欢迎小伙伴们提issues、我们共建。提升我们的开发体验。 vi…

(回溯分割)leetcode93 复原IP地址

#include<iostream> #include<vector> #include<string> #include<algorithm> using namespace std; //卡尔的图不是按照程序执行过程而是直接画程序会执行的过程 // 实际执行是&#xff1a;n个字符&#xff0c;递推n1后&#xff08;叶子节点&#xff…

Springboot3 自动装配流程与核心文件:imports文件

注&#xff1a;本文以spring-boot v3.4.1源码为基础&#xff0c;梳理spring-boot应用启动流程、分析自动装配的原理 如果对spring-boot2自动装配有兴趣&#xff0c;可以看看我另一篇文章&#xff1a; Springboot2 自动装配之spring-autoconfigure-metadata.properties和spring…

JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收 我们会把堆内存中的对象间隔一段时间做一次GC&#xff08;即垃圾回收&#xff09;&#xff0c;但是堆内存很大一块&#xff0c;内存布局分为新生代和老年代、其对象的特点不一样&#xff0c;所以回收的策略也应该各不相同 对于“刚出生”的新对象&#xf…

“腾讯、钉钉、飞书” 会议开源平替,免费功能强大

在数字化时代&#xff0c;远程办公和线上协作越来越火。然而&#xff0c;市面上的视频会议工具要么贵得离谱&#xff0c;要么功能受限&#xff0c;甚至还有些在数据安全和隐私保护上让人不放心。 今天开源君给大家安利一个超棒的开源项目 - Jitsi Meet&#xff0c;这可是我在网…

CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)

CNN-GRU卷积门控循环单元时间序列预测&#xff08;Matlab完整源码和数据&#xff09; 目录 CNN-GRU卷积门控循环单元时间序列预测&#xff08;Matlab完整源码和数据&#xff09;预测效果基本介绍CNN-GRU卷积门控循环单元时间序列预测一、引言1.1、研究背景与意义1.2、研究现状1…

状态模式——C++实现

目录 1. 状态模式简介 2. 代码示例 3. 单例状态对象 4. 状态模式与策略模式的辨析 1. 状态模式简介 状态模式是一种行为型模式。 状态模式的定义&#xff1a;状态模式允许对象在内部状态改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。 通俗的说就是一个对象…

大华相机DH-IPC-HFW3237M支持的ONVIF协议

使用libONVIF C库。 先发现相机。 配置 lib目录 包含 编译提示缺的文件&#xff0c;到libonvif里面拷贝过来。 改UDP端口 代码 使用msvc 2022的向导生成空项目&#xff0c;从项目的main示例拷贝过来。 CameraOnvif.h #pragma once#include <QObject> #include &l…

WIN11 UEFI漏洞被发现, 可以绕过安全启动机制

近日&#xff0c;一个新的UEFI漏洞被发现&#xff0c;可通过多个系统恢复工具传播&#xff0c;微软已经正式将该漏洞标记为追踪编号“CVE-2024-7344”。根据报告的说明&#xff0c;该漏洞能让攻击者绕过安全启动机制&#xff0c;并部署对操作系统隐形的引导工具包。 据TomsH…

Kyligence AI 数据智能体:首批亮相神州数码 DC·AI 生态创新中心!

近日&#xff0c;跬智信息&#xff08;Kyligence&#xff09;长期合作伙伴神州数码&#xff0c;其 DCAI 生态创新中心正式启幕。 作为首批生态伙伴&#xff0c;Kyligence AI 数据智能体也正式入驻&#xff0c;在这里首次亮相。 Kyligence 是国内最早推出 AI 用数产品的厂商&a…

GS论文阅读--Hard Gaussian Splatting

前言 本文也是对高斯点云的分布进行优化的&#xff0c;看&#xff01; 文章目录 前言1.背景介绍2.关键内容2.1 位置梯度驱动HGS2.2 渲染误差引导HGS 3.文章贡献 1.背景介绍 在训练过程中&#xff0c;它严重依赖于视图空间位置梯度的平均幅度来增长高斯以减少渲染损失。然而&…

消息队列篇--原理篇--Pulsar(Namespace,BookKeeper,类似Kafka甚至更好的消息队列)

Apache Pulusar是一个分布式、多租户、高性能的发布/订阅&#xff08;Pub/Sub&#xff09;消息系统&#xff0c;最初由Yahoo开发并开源。它结合了Kafka和传统消息队列的优点&#xff0c;提供高吞吐量、低延迟、强一致性和可扩展的消息传递能力&#xff0c;适用于大规模分布式系…

当 Facebook 窥探隐私:用户的数字权利如何捍卫?

随着社交平台的普及&#xff0c;Facebook 已经成为全球用户日常生活的一部分。然而&#xff0c;伴随而来的隐私问题也愈发严峻。近年来&#xff0c;Facebook 频频被曝出泄露用户数据、滥用个人信息等事件&#xff0c;令公众对其隐私保护措施产生质疑。在这个信息化时代&#xf…

OSCP - Proving Grounds - Quackerjack

主要知识点 端口转发 具体步骤 执行nmap扫描,开了好多端口&#xff0c;我先试验80和8081&#xff0c;看起来8081比较有趣 Nmap scan report for 192.168.51.57 Host is up (0.0011s latency). Not shown: 65527 filtered tcp ports (no-response) PORT STATE SERVICE …

Hive之加载csv格式数据到hive

场景&#xff1a; 今天接了一个需求&#xff0c;将测试环境的hive数据导入到正式环境中。但是不需要整个流程的迁移&#xff0c;只需要迁移ads表 解决方案&#xff1a; 拿到这个需求首先想到两个方案&#xff1a; 1、将数据通过insert into语句导出&#xff0c;然后运行脚本 …

PHP如何封装项目框架达到高可用、高性能、高并发

很多初创公司为了快速上线业务&#xff0c;开发时间由本来的6个月压缩到3个月甚至2个月。开发人员只能根据时间及业务需求去git上找现有的项目二次开发或者是一个空框架根据业务一点一点的去做&#xff0c;上述两种方案虽然也可以上线但是对于业务本身存在的问题也是很大的&…