STL-string(使用和部分模拟实现)

1.string

basic_string<char> 是 C++ 标准库中定义的一个模板类型,用于表示一个字符串。这个模板类接收一个字符类型作为模板参数。
typedef basic_string<char> string:string类是basic_string类模板的实例化,它使用 char作为其字符类型。

2.iterator迭代器

迭代器是类似指针的东西,但不一定是指针,迭代器可以用自定义类型实现

C++标准库提供了多种迭代器,不同类型的迭代器可以在不同的场景中使用:

1. 输入迭代器(单向,只读) (Input Iterator)
   - 允许只读访问元素。
   - 可以对序列进行一个方向的遍历。
   - 只能*解引用一次,每个元素只能读取一次。
   - 示例:std::istream_iterator

2. 输出迭代器(单向,只写) (Output Iterator)

   - 将数据写入序列中
   - 允许对元素的写操作。
   - 只能对序列进行一个方向的遍历。
   - 和输入迭代器一样,每个元素只能写入一次。
   - 示例:std::ostream_iterator

3. 前向迭代器(单向,可读可写,可以多次访问) (Forward Iterator)
   - 可以多次解引用。
   - 支持单向遍历。
   - 可以在迭代中保留状态,适合于需要多次访问同一个元素的场景。
   - 示例:std::forward_list,std::list

4. 反向迭代(单向,可读可写,可以多次访问)(Reverse Iterator)
   - 可以多次解引用。
   - 支持反向向遍历。
   - 可以在不改变容器本身的情况下,从容器的最后一个元素开始向前访问每个元素,直到访问到第一个元素
   -在 C++ STL 中,反向迭代器通常通过 rbegin() 和 rend() 方法获取

5. 双向迭代器(双向,可读可写,可以多次访问) (Bidirectional Iterator)
   - 可以在两个方向上遍历(即前向和后向)。
   - 支持多次解引用。
   - 没有减法,不能[]访问
   - 示例:std::list, std::set, std::map

6. 随机访问迭代器 (双向,可读可写,可以多次访问,支持随机访问)(Random Access Iterator)
   - 允许在常数时间内访问任意元素。
   - 支持所有双向迭代器的特性,并且可以进行加法、减法、比较等操作,可以[]访问。
   - 示例:std::vector, std::deque, std::array

3.string的使用

3.1 构造函数

void test1()
{string s1;//默认构造string s2(s1);//拷贝构造char s[] = "abc123";string s3(s);//对c风格字符串进行拷贝string s4(s3, 3, 2);//从s3的pos=3位置开始拷贝两个字符string s5(s3, 2);//从s3的pos=2位置开始拷贝直到s3结束string s6("abcdddd", 4);//对c风格字符串进行4个元素拷贝string s7('s', 3);//用3个‘s’初始化///用迭代器初始化//函数模板,支持不同类的迭代器vector<char> v(10);char ch = 'a';for (auto& c : v){c = ch++;}string s8(v.begin(), v.end());
}

size_t len = npos:
npos等于-1,size_t的-1赋值给len表示整型最大值,实际意思是用npos缺省时拷贝到底,有多少拷贝多少,len超出原有长度也是拷贝到底。

 3.2析构函数

 不需要自己调用

3.3operator=赋值运算符重载

void test2()
{string s1,s2;s1 = "123456";s2 = s1;cout << s1 << endl;cout << s2 << endl;s1 = 'a';s2 = "abcdef";cout << s1 << endl;cout << s2 << endl;
}

使用赋值运算符时,会对原有数据进行覆盖

要分清拷贝构造和赋值:

 

 3.4 begin()

返回字符串开头的迭代器
迭代器是随机访问迭代器
const_iterator begin() const用于const对象,返回的迭代器解引用无法进行修改
迭代器it++向后遍历

void test3()
{string s("abcdefg");std::string::iterator it = s.begin();while (it != s.end()){cout << *it;it++;}	cout << endl;it = s.begin();while (it != s.end()){*it += 2;cout << *it;it++;}
}
void test4()
{const string s("11111222233333");std::string::const_iterator it = s.begin();while (it != s.end()){cout << *it;it++;}cout << endl;//it = s.begin();//while (it != s.end())//{//	*it += 2;//it指向内容不可修改//	cout << *it;//	it++;//}
}

3.5end()

返回字符串最后一位有效数据的下一位的迭代器
迭代器是随机访问迭代器
const_iterator begin() const用于const对象,返回的迭代器解引用无法进行修改
如果对象是空字符串,begin()和end()返回相同的迭代器(迭代器支持比较)
begin()与end()的范围是左闭右开[)

3.6 rbegin() 和 rend()

返回最后一位有效数据的反向迭代器
返回反向迭代器以反向开始
反向迭代器++向字符串的开头遍历

void test5()
{string s("abcdefg");std::string::reverse_iterator rit = s.rbegin();while (rit != s.rend()){cout << *rit;rit++;}cout << endl;;rit = s.rbegin();while (rit != s.rend()){*rit += 3;cout << *rit;rit++;}
}
void test6()
{const string s("abcdefg");std::string::const_reverse_iterator rit = s.rbegin();while (rit != s.rend()){cout << *rit;rit++;}//cout << endl;;//rit = s.rbegin();//while (rit != s.rend())//{//	*rit += 3;//const对象,const_reverse_iterator指向的内容不可以修改//	cout << *rit;//	rit++;//}
}

 3.7 rend()

将反向迭代器返回到反向结束
返回一个反向迭代器,该迭代器指向字符串第一个有效数据的前一个(作为反向结尾)
rbegin()和rend()表示范围:(]

3.8 cbegin() 和 cend(()

 与begin()和end()的区别:begin()和end()返回的迭代器可读可写,cbegin() 和 cend() 返回的迭代器是const_iterator只读不写,即便调用的对象本身是可读可写的。

3.9 crbegin() 和 crend()

 与rbegin()和rend()的区别:rbegin()和rend()返回的迭代器可读可写,crbegin() 和 crend() 返回的迭代器是const_reverse_iterator只读不写,即便调用的对象本身是可读可写的。

3.10 size()

 返回字符串的长度(不算'\0')

3.11 length()

返回字符串的长度(不算'\0')
跟size()作用是一样的

在 C++ 早期版本的标准库及其与 STL(标准模板库)的设计过程中,可能出于兼容性和可读性的考虑,保留了这两个方法。length() 方法是更早设计的,而 size() 方法也在其他 STL 容器中得到了广泛应用。
许多 STL 容器(如 std::vectorstd::deque 等)也提供了 size() 方法。因此,为了保持与其他容器的一致性,std::string 中也引入了 size() 方法。调用 size() 对于开发者来说,更符合 STL 的使用习惯。

3.12 max_size()

返回字符串可以达到的最大长度。
但实际上并不能达到最大长度,所以max_size()没什么用

 3.13 resize()

作用:将字符串的长度调整至n个长度;如果n小于原长,则会删除n长度以外的数据;如果n大于原长且没有指定字符c当初始值,则使用空字符('\0')来初始化,而且此时的长度是n;指定字符c当初始值则将原数据以外的位置全部给c初始值

void test10()
{string s("abcdefg");cout << s.size() << endl;s.resize(3);cout << s.size() << endl;cout << s << endl;s.resize(10);cout << s.size() << endl;cout << s << endl;
}

3.14 capacity()

 返回已分配容量的大小(单位:字节)

 长度size不一定等于容量大小capacity。

3.15 reserve()

请求将字符串容量调整为计划的大小更改,长度最多为n个字符
当n大于当前字符串容量时,扩容到n个大小
当n小于等于字符串容量时,这被认为是一个非强制性的请求,具体操作不同编译器下不同


在vs2022下:没办法通过reserve缩容(即使有些空间没有使用):

3.16 clear()

 清空字符串,将长度size置为0,不改变容量capacity

3.17 empty()

判断是否为空字符串,如果为空返回true,如果不为空返回false

3.18 shrink_to_fit()

请求字符串减少其容量以适合其大小。

 3.19 operator[]

返回pos位置的引用(const对象数据不可修改)
当pos等于size() 长度时,返回'\0'

普通数组[]访问越界可能没有报错,string[]访问越界直接报错(有assert进行越界检查)

 3.20 at()

返回pos位置的引用(const对象数据不可修改)
当pos等于size() 长度时,返回'\0'

at()与operator[] 的区别:底层处理越界不同,[]是暴力检查assert,at可以被捕获异常

3.21 back()

返回字符串最后一个字符的引用
空字符串无法调用

 3.22 front()

返回字符串第一个字符的引用
空字符串无法调用 

3.23 operator+=

在当前字符串后面追加字符串(或字符)并返回追加后的字符串的引用

3.24 append()

 在当前字符串后面追加字符串(或字符)并返回追加后的字符串的引用

void test20()
{string s("123456789");s.append(s);//s后面追加一个ss.append(s, 4,5);//从s的4位置开始9后面5个字符追加到s后面s.append("abc");//s后面追加c风格的字符串s.append("def", 2);//s后面追加c风格的前2个字符s.append(10,'u');//s后面追加10个字符'u'cout << s << endl;vector<char> v(10);for (int i = 0; i < 10; i++){v[i] = 'a' + i;}s.append(v.begin(), v.end());//使用迭代器范围追加cout << s << endl;
}

 3.25 push_back()

尾插一个字符

3.26 assign()

为字符串分配一个新值,替换其当前内容 

3.27 insert()

指定原字符串的pos位置开始插入字符或字符串
重载函数返回iterator指向新插入字符的位置

3.28 erase()

删除字符串的一部分
重载函数返回iterator指向被删除部分的下一位

3.29 replace()

替换字符串的一部分

3.30 swap()(string成员函数)

交换两个对象的数据

3.31 pop_back()

 删除最后一个字符

3.32 c_str()

将对象转换成c风格的字符串,并返回其const修饰的指针,不可修饰指针指向的内容

 

3.33 data()

返回一个指向字符串内部字符数组的指针。这个指针可以用来直接访问字符串中的字符。

3.34 get_allocator()

用于获取与该容器关联的分配器(allocator)
返回一个分配器对象,这个对象用于在容器内部分配和释放内存
分配器是一个用于管理动态内存分配的对象,允许用户在使用 STL 容器时自定义内存管理行为

void test3()
{string s("abcdefghijklmnopq");// 获取与 s 关联的分配器std::allocator<char> alloc = s.get_allocator();//使用分配器分配内存--分配10个字符的内存char* p = alloc.allocate(10);//使用分配器释放内存alloc.deallocate(p, 10);
}

3.35 copy()

将字符串对象的当前值的子字符串复制到 s 指向的数组中。此子字符串包含从位置pos开始的len个字符
返回复制的字符个数
注意:函数不会在复制内容的末尾附加 '\0 '字符

3.36 find()

在字符串中正序搜索由其参数指定的序列第一次出现的字符或字符串,并返回第一个字符的pos

void test5()
{string s("abc11112345");size_t pos = s.find("123",0);cout << pos << endl; //6size_t pos1 = s.find("bcdef", 0, 2);//搜索"bcdef"的前两位"bc"cout << pos1 << endl; //1size_t pos2 = s.find('1');cout << pos2 << endl; //3
}

3.37 rfind()

在字符串中逆序搜索由其参数指定的序列最后一次出现的字符或字符串,并返回第一个字符的pos 

void test5()
{string s("abc123612345");size_t pos = s.rfind("123", s.size() - 1);cout << pos << endl; //7size_t pos1 = s.rfind("bcdef", s.size() - 1, 2);//搜索"bcdef"的前两位"bc"cout << pos1 << endl; //1size_t pos2 = s.rfind('1');cout << pos2 << endl; //7
}

3.38 find_first_of()

 在字符串中正序搜索与其参数中指定的序列中任何字符匹配(有一个字符匹配即可)的第一个字符,并返回其pos

void test6()
{string s("112334567");size_t pos = s.find_first_of("asdf2");cout << pos << endl; // 2
}

3.39 find_last_of()

在字符串中逆序搜索与其参数中指定的序列中任何字符匹配(有一个字符匹配即可)的第一个字符,并返回其pos

void test6()
{string s("1123345267");size_t pos = s.find_last_of("asdf2");cout << pos << endl; // 7
}

3.40 find_first_not_of()

 在字符串中正序搜索第一个字符,该字符与其参数中指定的任何字符都不匹配,并返回对应的pos

void test7()
{string s("123456665");size_t pos = s.find_first_not_of("asdf", 0);cout << pos << endl; //0size_t pos1 = s.find_first_not_of("12346", 0);cout << pos1 << endl; // 4
}

3.41 find_last_not_of()

在字符串中逆序搜索第一个字符,该字符与其参数中指定的任何字符都不匹配,并返回对应的pos 

void test7()
{string s("123456665");size_t pos = s.find_last_not_of("asdf", s.size() - 1);cout << pos << endl; // 8size_t pos1 = s.find_last_not_of("12346", s.size() - 1);cout << pos1 << endl; // 8
}

3.42 substr()

构造一个子字符串并返回

3.43 compare()

将字符串对象(或子字符串)的值与其参数指定的字符序列进行比较
>返回1, == 返回0, <返回-1
 

3.44 operator+(非成员函数)

构造一个新字符串,lhs的后面尾接rhs

3.45 各种运算符重载

3.46 swap()(非成员函数)

假设调用两个string对象调用上面的swap,swap会先拷贝构造一个对象,再进行交换,这样做代价太大,实际上只需要交换这两个对象的数据即可,所以标准库里重载了一个非成员函数专门给string使用,以防调用上面代价大的方式

这个swap会直接交换两个对象的数据

3.47 operator>> 和 operator<< (非成员函数)

 cin默认规定空格或换行是多个值之间的分割

 

3.48 getline() (非成员函数) 

getline可以自定义分隔符,遇到分割符才截至,默认遇到换行才截至,空格不截至,当自定义分割符时,换行不再充当分割符

4.string遍历

4.1 下标+[] 访问

void test12()
{string s = "abcdefgh";for (int i = 0; i < s.size(); i++){s[i] += 1;cout << s[i] << ' ';}
}

4.2 迭代器访问(主流的通用访问方式)

void test13()
{string s = "abcdefgh";string::iterator it = s.begin();while (it != s.end()){(*it) += 1;cout << (*it) << ' ';it++;}
}

4.3 范围for(底层是用迭代器实现的)

void test14()
{string s = "abcdefgh";for (auto& c : s){c += 1;}for (auto c : s){cout << c << ' ';}
}

数组和所有容器都支持范围for,因为底层是由迭代器实现的,容器都可以通过迭代器遍历

5.const_iterator 和 iterator

void test15()
{string s("123456");string::iterator it = s.begin();//const_iterator指向的内容不能修改const string s1("abc");string::const_iterator it1 = s.begin();//const iterator指it2不能修改,it2指向的内容可以修改string s2("aaaa");const string::iterator it2 = s2.begin();*it2 = 'b';cout << s2 << endl;
}

6.sort() 算法

sort()函数是算法库里面模板函数,支持随机访问迭代器
sort()函数默认升序排序(<升序,>降序)
实现降序需要传递仿函数

void test16()
{string s("anfaskdnvqruqwoetufvvzx");sort(s.begin(), s.end());cout << s << endl;//gt仿函数是greater类型的对象,greter类型支持大小的比较(>)greater<char> gt;sort(s.begin(), s.end(), gt);cout << s << endl;//ls仿函数是less类型的对象,less类型支持大小的比较(<)less<char> ls;sort(s.begin(), s.end(), ls);cout << s << endl;//匿名对象写法sort(s.begin(), s.end(), greater<char>());cout << s << endl;
}

 

7.reverse()

用于反转范围内的元素

 

8.string的扩容

string如何扩容,c++标准没有规定,具体实现取决于编译器实现

vs2022下:

vs2022下,string默认有个16字节的_Buf数组,其中一个字节是留给'\0'的,剩下15字节作为容量,当所需容量小于15字节,string字符存在_Buf数组中;当所需空间大于15字节时,再动态开辟内存将所有字符存在开辟的内存中



Linux下:

9. shrink_to_fit() 的缩容

由于空间不能分段释放,所以缩容时会另开一块更小的空间,再将数据进行拷贝,释放原来的空间

10.to_string() 和 stoi

将数值转换成string并返回

 

string转换成整型并返回

11.string部分底层简单模拟实现

//string.h#define  _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <iostream>
#include <assert.h>using namespace std;namespace myString
{class string{public://可以不用iterator直接用char*//把迭代器进行封装typedef char* iterator;typedef const char* const_iterator;iterator begin();iterator end();const_iterator begin() const;const_iterator end() const;//string();//""默认有一个'\0'string(const char* str = "");string(const string& str);~string();const char* c_str() const;//string& operator=(const string& str);string& operator=(string str);size_t size() const;char& operator[] (size_t pos);const char& operator[] (size_t pos)const;void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+= (char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void earse(size_t pos, size_t len = npos);void swap(string& str);string substr(size_t pos = 0, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);bool operator<(const string& str)const;bool operator<=(const string& str)const;bool operator>(const string& str)const;bool operator>=(const string& str)const;bool operator==(const string& str)const;bool operator!=(const string& str)const;void clear(); private://char _buff[16];char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;//静态成员变量不能给缺省值,因为不走初始化列表//特例:static的const的整型可以给缺省值--既是声明也是定义const static size_t npos;};ostream& operator<<(ostream& os, const string& str);istream& operator>>(istream& is, string& str);
}
//string.cpp#include "string.h"//这样是因为多个文件同一个命名空间会合并
namespace myString
{//static 成员变量类内声明,类外定义//static成员变量属于静态区,若在string.h定义,在多文件展开就会冲突const size_t string::npos = -1;string::iterator string:: begin(){return _str;}string::iterator string::end(){return _str + _size;}string::const_iterator string::begin() const{return _str;}string::const_iterator string::end() const{return _str + _size; }//错误写法//可能出现解引用nullptr的错误//string::string()//{//	_str = nullptr;//	_size = _capacity = 0;//}//strlen不算入'\0'//_size不算入'\0'//_capacity不算入'\0'string::string(const char* str):_size(strlen(str)){//""会被strcpy拷贝过去//+1是因为'\0'_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);}传统写法//string::string(const string& str)//{//	_str = new char[str._capacity + 1];//	strcpy(_str, str._str);//	_size = str._size;//	_capacity = str._capacity;//}// //现代写法(特点:让别人干活,再交换)string::string(const string& str){//调用构造干活string tmp(str._str);swap(tmp);}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* string::c_str() const{return _str;}传统写法//string& string::operator=(const string& str)//{//	if(this != &str)//	{//		char* tmp = new char[str._capacity + 1];//		strcpy(tmp, str._str);//		delete[] _str;//		_str = tmp;//		_size = str._size;//		_capacity = str._capacity;//	}//	return *this;//}现代写法//string& string::operator=(const string& str)//{//	if (this != &str)//	{//		string tmp(str._str);//		swap(tmp);//	}//	return *this;//}//现代写法再进化string& string::operator=(string str){//str局部对象,出了作用域析构swap(str);return *this;}size_t string::size() const{return _size;}char& string::operator[] (size_t pos){assert(pos < _size && pos >= 0);return _str[pos];}const char& string::operator[] (size_t pos)const{assert(pos < _size && pos >= 0);return _str[pos];}void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if(_size == _capacity){size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newCapacity);}_str[_size] = ch;_str[++_size] = '\0';}void string::append(const char* str){size_t len = strlen(str);if(_size + len > _capacity){reserve(_size + len);}//不用strcat('\0'问题,而且从头遍历效率不高),用strcpy就行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;}void string::insert(size_t pos, char ch){assert(pos >= 0 && pos <= _size);if (_size == _capacity){size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newCapacity);}//方法1://int end = _size;//while (end >= (int)pos)//类型不同,发生隐式类型转换,有符号转换成无符号//{//	_str[end + 1] = _str[end];//	--end;//}//方法2: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 >= 0 && pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];--end;}memcpy(_str + pos, str, len);_size += len;}void string::earse(size_t pos, size_t len){assert(pos >= 0 && pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}}void string::swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}string string::substr(size_t pos, size_t len){if (len > _size - pos){string sub(_str + pos);return sub;}else{string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}}}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){const char* p = strstr(_str + pos , str);return p - _str;}bool string::operator<(const string& str)const{return strcmp(_str, str._str) < 0;}bool string::operator<=(const string& str)const{return *this < str || *this == str;}bool string::operator>(const string& str)const{return strcmp(_str, str._str) > 0;}bool string::operator>=(const string& str)const{return !(*this < str);}bool string::operator==(const string& str)const{return strcmp(_str, str._str) == 0;}bool string::operator!=(const string& str)const{return !(*this == str);}void string::clear(){_str[0] = '\0';_size = 0;}ostream& operator<<(ostream& os, const string& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}缺点:频繁扩容//istream& operator>>(istream& is, string& str)//{//	str.clear();//	char ch = is.get();//	while (ch != ' ' && ch != '\n')//	{//		str += ch;//		ch = is.get();//	}//	return is;//}//cin优化方案--模拟缓冲区减少扩容的次数istream& operator>>(istream& is, string& str){str.clear();char buff[128];int i = 0;char ch = is.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[i] = '\0';str += buff;i = 0;}ch = is.get();}if (i != 0){buff[i] = '\0';str += buff;}return is;}
}

12.实现过程中的一些问题

12.1 #include问题

#include "" 双引号默认在源文件当前目录下查找,找不到再去标准库里查找
#include <>是直接在标准库里查找
 

12.2 不同文件相同命名空间

多个文件同一个命名空间会合并

12.3 delete和free可以对nullptr

在C++中,delete 和 free 对 nullptr 的行为是安全的,可以安全地对 nullptr 调用,而不会造成任何问题。

12.4 实现范围for

范围for的底层就是迭代器,自己定义的类需要自己实现迭代器就能使用范围for(一定要实现begin()和end(), 且函数名字不能变,iterator可以变名字)

12.5 strcat()

strcat会从头开始遍历找'\0',覆盖找到的'\0'开始拼接,并在拼接后的字符串添加'\0'

12.6 静态成员变量

静态成员变量不能给缺省值,因为不走初始化列表
特例:static的const的整型可以给缺省值--既是声明也是定义
static 成员变量类内声明,类外定义
static 成员变量属于静态区,若在string.h定义,在多文件展开就会冲突

12.7 引用计数的写时拷贝(延时拷贝)

深拷贝需要重新开辟空间再进行赋值,浅拷贝只是将地址按字节拷贝,假设构造的这个对象不进行修改操作,可以直接用浅拷贝减少深拷贝的消耗。

浅拷贝的问题及其解决:
1.不同对象指向同一块资源,导致析构两次报错
解决方法:用引用计数,在析构函数内部对引用计数进行判断,使最后一个析构的对象释放空间。
2.一个修改影响另一个
解决方法:写时拷贝,需要修改的对象重新开辟并指向新的空间,然后进行拷贝并修改,不修改的对象仍然指向原来的空间

不修改就赚了,可以提升效率,linux下使用这个方案

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

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

相关文章

狗都能看懂的Actor-Critic强化学习算法讲解

Review Policy Gradient 上面的公式是Policy Gradient的更新函数&#xff0c;这个式子是指在 s t s_t st​时刻采取了 a t a_t at​&#xff0c;计算出对应发生的概率 p θ p_\theta pθ​&#xff0c;然后计算在采取了这个 a t a_t at​之后&#xff0c;所得到的reward有多大。…

优化算法|自适应大邻域搜索算法及MATLAB代码实现

回来填坑了&#xff0c;本篇推文将详细讲解ALNS算法求解VRP问题及MATLAB代码实现。 算法介绍 节约算法构造初始解 function routessaving_init(DistMatrix, Demand, Cap) C_EPS1e-1;Nsize(DistMatrix,1); routescell(numel(2:N),1); for i1:numel(routes) % 每个节点单独一条…

【Django】前端技术HTML常用标签(开发环境vscode)

文章目录 安装两个常用插件HTML常用标签定义文档类型DOCTYPE网页的结构html/head//title/body/div标题h1/h2/h3/h4/h5分割线hr段落 p列表ul/li&#xff0c;ol/li超链接a文本span图片img按钮button表格table&#xff08;table、tr、th、td&#xff09;表单form 安装两个常用插件…

目标检测 YOLOv5-7.0 详细调试自制数据集实战

目标检测 YOLOv5-7.0 详细调试&自制数据集实战 一、项目介绍及环境配置&#xff08;一&#xff09;项目解读&#xff08;二&#xff09;版本选择&#xff08;三&#xff09;环境配置 二、如何利用YOLOv5进行预测&#xff08;detect.py&#xff09;&#xff08;一&#xff0…

Windows 实用小工具:窗口钉子/文件管理 2024/7/27

一: wintop 窗口置顶工具 二:WinDirStat 这是一个免费的、开源的磁盘使用分析工具&#xff0c;适用于Windows系统。它会扫描你的硬盘&#xff0c;列出所有文件和文件夹的大小&#xff0c;并以图形化的方式展示&#xff0c;便于理解。 可以用来检测硬盘文件夹占用从而,酌情处…

JAVA.抽象、接口、内部类

1.抽象 共性&#xff0c;父类定义抽象方法&#xff0c;子类必须重写&#xff0c;或者子类也是抽象类 示例代码 animal package animalabstract;//定义抽象类animal public abstract class animal {String name;int age;//定义抽象方法eat&#xff0c;子类必须重写public abs…

Java给定一些元素随机从中选择一个

文章目录 代码实现java.util.Random类实现随机取数(推荐)java.util.Collections实现(推荐)Java 8 Stream流实现(不推荐) 完整代码参考&#xff08;含测试数据&#xff09; 在Java中&#xff0c;要从给定的数据集合中随机选择一个元素&#xff0c;我们很容易想到可以使用 java.…

【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件

目录 ​编辑 前言 系统调用 open 参数flags 参数mode write 追加方式 read close 文件描述符 打开多个文件并观察其文件描述符 C语言文件操作 理解一切皆文件 理解open操作 前言 各类语言的文件操作其实是对系统调用的封装 我们经常说&#xff0c;创建一个文件&a…

力扣第三十七题——解数独

内容介绍 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 数独…

CVE-2024-39700 (CVSS 9.9):JupyterLab 模板中存在严重漏洞

在广泛使用的 JupyterLab 扩展模板中发现了一个严重漏洞&#xff0c;编号为CVE-2024-39700 。此漏洞可能使攻击者能够在受影响的系统上远程执行代码&#xff0c;从而可能导致大范围入侵和数据泄露。 该漏洞源于在扩展创建过程中选择“测试”选项时自动生成“update-integratio…

VIM基础配置

1. CTAGS配置 下载 上传虚拟机&#xff0c;解压&#xff0c;进入目录 tar -xzvf ctags-5.8.tar.gz cd ctags-5.8/编译 ./configure sudo make sudo make install查看是否安装成功 ctags --version打印如下 2. 使用Vundle 下载 git clone https://github.com/VundleVim/Vund…

Linux并发程序设计(3):守护进程

目录 前言 一、介绍 1.1 概念 1.2 特点 1.3 举例 二、系统编程 2.1 setsid函数 2.2 getpid函数 2.3 getsid函数 2.4 getpgid函数 2.5 chdir函数 三、代码例程 3.1 使子进程在后台运行 3.2 使子进程脱离原终端 3.3 更换目录&#xff0c;并设定权限&#xff08;非…

基于STM32通过云平台实现智慧大棚【手机远程查看温湿度】【报警】

文章目录 一、成果演示二、所用到的模块三、实现的功能四、接线说明五、WIFI模块配置步骤5.1云平台介绍5.2云平台使用5.3使用USB转TTL测试联通云平台 六、STM32代码编写七、手机上查看数据6.1下载软件&#xff08;仅限安卓手机&#xff09;6.2操作 一、成果演示 STM32通过物联网…

String、StringBuffer和StringBuilder

一、String类 1. String类的理解 2. String类结构 1. String类实现了Serializable接口,说明String对象可以串行化,即可以在网络上传输 2. String类实现了Comparable接口,说明String对象可以比较 String底层是一个字符数组,这个数组里存的是字符串的内容 例如:…

005 仿muduo实现高性能服务器组件_通信连接管理

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;仿muduo &#x1f4d2;代码仓库&#xff1a; 项目代码 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言Channel模块设计原因整体设计代码如下 Connection模块设计原…

Florence2:Advancing a unified representation for a variety of vision tasks

Florence-2模型:开启统一视觉基础模型的新篇章_florence -2-CSDN博客文章浏览阅读1.1k次,点赞108次,收藏109次。Florence-2是由微软Azure AI团队开发的一款多功能、统一的视觉模型。它通过统一的提示处理不同的视觉任务,表现出色且优于许多大型模型。Florence-2的设计理念是…

用Postman Flows打造你的专属API:外部公开,轻松上手!

引言 Postman Flows 是一个使用 GUI 进行无代码 API 调用流程创建的服务。这篇文章我尝试使用 Flows 来构建将 Momento Topic 中的数据保存到 TiDB 的保存 API&#xff0c;因此想分享一些使用过程中的技巧等。 实现内容 将从 Momento Topics 配发的 JSON 数据保存到 TiDB 中。…

C++ 栈( stack )学习

目录 1.栈 2.模拟栈 1.1.入栈( push ) 1.2.出栈( pop ) 1.3.获取栈顶元素( top ) 3.直接使用栈( stack ) 3.1.导入头文件并创建栈 3.2.栈的操作 3.2.1.入栈( push ) 3.2.2.出栈( pop ) 3.2.3.获取栈顶元素( top ) 3.2.4.获取栈中元素个数( size ) 3.2.5.判断栈是否…

代码随想录算法训练营day8 | 344.反转字符串、541.反转字符串 II、卡码网:54.替换数字

文章目录 344.反转字符串思路 541.反转字符串 II思路 卡码网&#xff1a;54.替换数字思路复习&#xff1a;字符串 vs 数组 总结 今天是字符串专题的第一天&#xff0c;主要是一些基础的题目 344.反转字符串 建议&#xff1a; 本题是字符串基础题目&#xff0c;就是考察 revers…