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

前言

目录

    • 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需要考虑完善的增删查改和使用的stringclass 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_backstring& 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);}//复用appendstring& 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都是0while (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.mzph.cn/diannao/8486.shtml

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

相关文章

Redis(主从复制搭建)

文章目录 1.主从复制示意图2.搭建一主多从1.搭建规划三台机器&#xff08;一主二从&#xff09;2.将两台从Redis服务都按照同样的方式配置&#xff08;可以理解为Redis初始化&#xff09;1.安装Redis1.yum安装gcc2.查看gcc版本3.将redis6.2.6上传到/opt目录下4.进入/opt目录下然…

iptables---防火墙

防火墙介绍 防火墙的作用可以理解为是一堵墙&#xff0c;是一个门&#xff0c;用于保护服务器安全的。 防火墙可以保护服务器的安全&#xff0c;还可以定义各种流量匹配的规则。 防火墙的作用 防火墙具有对服务器很好的保护作用&#xff0c;入侵者必须穿透防火墙的安全防护…

第V章-Ⅰ Vue3路由vue-router初识

第V章-Ⅰ Vue3路由vue-router初识 安装Vue路由基础router-link 组件导航router-view 路由出口单独导入关于路由的库文件定义路由组件定义路由规则对象创建router实例将路由对象挂载Vue实例上redirect 路由重定向嵌套路由 路由传参params形式传参query形式传参params方式与query…

Leetcode—1991. 找到数组的中间位置【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—1991. 找到数组的中间位置 实现代码 class Solution { public:int findMiddleIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size();…

考情分析 | 2025年西北工业大学计算机考研考情分析!

西北工业简称西工大&#xff08;英文缩写NPU&#xff09;&#xff0c;大学坐落于古都西安&#xff0c;是我国唯一一所以同时发展航空、航天、航海工程教育和科学研究为特色&#xff0c;以工理为主&#xff0c;管、文、经、法协调发展的研究型、多科性和开放式的科学技术大学。十…

代码随想录-算法训练营day33【贪心算法03:K次取反后最大化的数组和、加油站、分发糖果】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第八章 贪心算法 part03● 1005.K次取反后最大化的数组和 ● 134. 加油站 ● 135. 分发糖果 详细布置 1005.K次取反后最大化的数组和 本题简单一些&#xff0c;估计大家不用想着贪心 &#xff0c;用自己直觉也会有…

怎么制作好玩的gif?试试这个工具轻松制作

视频之所以受大众的喜爱是因为有声音、画面的搭配&#xff0c;让观者深入其中体验感会更强。但是视频的体积较大、时长也比较长&#xff0c;给我们的传播和保存造成了一定的影响。那么&#xff0c;我们可以将视频制作成gif图片来使用&#xff0c;不需要下载软件&#xff0c;使用…

最大数字——蓝桥杯十三届2022国赛大学B组真题

问题分析 这道题属于贪心加回溯。所有操作如果能使得高位的数字变大必定优先用在高位&#xff0c;因为对高位的影响永远大于对低位的影响。然后我们再来分析一下&#xff0c;如何使用这两种操作&#xff1f;对于加操作&#xff0c;如果能使这一位的数字加到9则变成9&#xff0…

LeetCode-hot100题解—Day6

原题链接&#xff1a;力扣热题-HOT100 我把刷题的顺序调整了一下&#xff0c;所以可以根据题号进行参考&#xff0c;题号和力扣上时对应的&#xff0c;那么接下来就开始刷题之旅吧~ 1-8题见LeetCode-hot100题解—Day1 9-16题见LeetCode-hot100题解—Day2 17-24题见LeetCode-hot…

UE5自动生成地形一:地形制作

UE5自动生成地形一&#xff1a;地形制作 常规地形制作地形编辑器地形管理添加植被手动修改部分地形的植被 置换贴图全局一致纹理制作地貌裸露岩石地形实例 常规地形制作 地形制作入门 地形导入部分 选择模式&#xff1a;地形模式。选择地形子菜单&#xff1a;管理->导入 …

STC8增强型单片机开发——C51版本Keil环境搭建

一、目标 了解C51版本Keil开发环境的概念和用途掌握C51版本Keil环境的安装和配置方法熟悉C51版本Keil开发环境的使用 二、准备工作 Windows 操作系统Keil C51 安装包&#xff08;可以从Keil官网下载&#xff09;一款8051单片机开发板 三、搭建流程 环境搭建的基本流程&#xf…

思维导图网页版哪个好?2024年值得推荐的8个在线思维导图软件!

思维导图如今已成为一种常用的工具&#xff0c;帮助我们清晰地组织和整理信息。随着科技的发展&#xff0c;思维导图的产品形态也经过多轮迭代&#xff0c;从最初的本地客户端过渡到基于云的 Web 端&#xff0c;各类网页版思维导图软件应运而生&#xff0c;它们方便快捷&#x…

【Linux】gcc/g++的使用

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解Linux中gcc/g使用的相关内容。 如果看到最后您觉得这篇文章写得不错…

【Linux】CAN根据时钟频率、波特率计算采样点详解

1、采样点知识回顾 参考博客:【CAN】知识点:帧类型、数据帧结构、传输速率、位时间、采样点 CAN 采样点是指在一个数据位的传输周期内,接收器实际采样数据的时间点。这个时间点是以百分比来表示的,它决定了在数据位的传输周期中,何时读取数据位的值。 正确设置采样点对…

js api part3

环境对象 环境对象&#xff1a; 指的是函数内部特殊的 变量 this &#xff0c; 它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 函数的调用方式不同&#xff0c;this 指代的对象也不同 【谁调用&#xff0c; this 就是…

Qt | QLineEdit 类(行编辑器)

01、上节回顾 Qt | QComboBox(组合框)02、QLineEdit 1、QLineEdit 类是 QWidget 类的直接子类,该类实现了一个单行的 输入部件,即行编辑器,见右图 2、验证器(QValidator 类)和输入掩码简介:主要作用是验证用户输入的字符是否符合验证器 的要求,即限制对用户的输入,比…

【C#_变量_格式化输出_If语句_微信猜拳_第一篇】

C#&#xff08;编程入门&#xff09; 练习来自腾讯课堂免费课程1.1.基本输出语句基本输出语句——知识点总结Console.Clear();清屏字符串和数字区分Console.ReadLine(); 1.2.变量的基本使用&#xff1a;变量的基本使用——知识点总结 1.3.格式化输出格式化输出——知识点总结 1…

01 设计模式--单例模式

1. 单例模式 单例模式有两种实现方式&#xff1a; 1.1 饿汉模式&#xff08;Eager Initialization&#xff09;&#xff1a;在类加载时就创建单例实例&#xff0c;无论是否需要使用该实例。 饿汉模式在类加载时就创建单例实例&#xff0c;无论是否需要使用该实例。 饿汉模式…

C++ Primer 中文版(第 5 版)-第二单元

第二单元 练习 2.1 通过读下面程序&#xff0c;写出程序运行结果。 #include <iostream>int main() {unsigned u 10, u2 42;std::cout << u2 - u << std::endl;std::cout << u - u2 << std::endl;int i 10, i2 42;std::cout << i2 …

论文阅读_使用有向无环图实现流程工程_AgentKit

英文名称: AgentKit: Flow Engineering with Graphs, not Coding 中文名称: AgentKit&#xff1a;使用图而非编码进行流程工程 链接: https://arxiv.org/pdf/2404.11483.pdf 代码: https://github.com/holmeswww/AgentKit 作者: Yue Wu, Yewen Fan, So Yeon Min, Shrimai Prabh…