• STL的学习之一


    1)STL扫盲

    1)C++标准库和标准模板库是不一样的
    2)标准模板库是用泛型编程方式编写的函数或者类库;
    3)  SGI STL linux一般用,P.J.Plauger STL,visual2017 windows用
    STL六大组件 :
    容器,迭代器
    STL 算法(说白了就是函数!);
    STL 分配器:(分配内存的,也叫内存分配器)allocator [ˈæləˌkeɪtə]
    适配器和仿函数
    convert 转换,converge 汇聚,收敛
    容器分类:顺序容器,关联容器(associate [əˈsəʊsɪˌcontainer),无序容器;注意:associate的第一个as是ad变体,表示靠近的意思
    deque 双端队列:double end queue
    foward_list是单向链表
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2)stl::array中,存储的字符串时,内存关系案例:

    #include
    #include
    
    using namespace std;
    
    int main()
    {
    	array<string, 5> arr{ "1232222222222222222","456","aaaaaaa"};
    	cout << sizeof(string) << endl; //28个字节
    	for (int i = 0; i < arr.size(); ++i)
    	{
    		const char* p = arr[i].c_str();
    		cout << "---------------------begin-----------------" << endl;
    		cout << "数组元素值= " << p << endl;
    		printf("对象地址= %p\n", &arr[i]);
    		printf("指向字符串地址= %p\n", p);
    		cout << "---------------------end-----------------" << endl;
    		cout << endl;
    	}
    	const char* p1 = "1232222222222222222";
    	const char* p2 = "1232222222222222222";
    	printf("p1地址= %p\n", p1);
    	printf("p2地址= %p\n", p2);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    //输出结果
    28
    ---------------------begin-----------------
    数组元素值= 1232222222222222222
    对象地址= 012FFA74
    指向字符串地址= 016BD988
    ---------------------end-----------------

    ---------------------begin-----------------
    数组元素值= 456
    对象地址= 012FFA90
    指向字符串地址= 012FFA94
    ---------------------end-----------------

    ---------------------begin-----------------
    数组元素值= aaaaaaa
    对象地址= 012FFAAC
    指向字符串地址= 012FFAB0
    ---------------------end-----------------

    ---------------------begin-----------------
    数组元素值=
    对象地址= 012FFAC8
    指向字符串地址= 012FFACC
    ---------------------end-----------------

    ---------------------begin-----------------
    数组元素值=
    对象地址= 012FFAE4
    指向字符串地址= 012FFAE8
    ---------------------end-----------------

    p1地址= 0094DC74
    p2地址= 0094DC74

    //从以上结果可知:1)字符串string字节大小为28,2)array中的string数组地址相差28个字节,但指向的字符串地址是不挨着的。
    //3 定义两个字符串常量,但其存储的字符串地址其实只有一个地址!!!
    3)vector的构造拷贝学习

    #include
    #include
    #include
    using namespace std;
    
    class A
    {
    public:
    	A(int a) :m_(a) { cout << "A constructor" << endl; }
    	A(const A& obj):m_(obj.m_){ cout << "A copy constructor" << endl; }
    	~A(){ cout << "A deconstructor" << endl; }
    private:
    	int m_;
    };
    
    int main()
    {
    	vector<A> vec;
    	//vec.reserve(10); 根据实际情况,调用这个函数,设置存储空间大小,就可以减少不必要的拷贝和析构;
    	for (int i = 0; i < 5; i++)
    	{
    		cout << "---------------------begin-----------------" << endl;
    		vec.push_back(A(i));
    		cout << "---------------------end-----------------" << endl;
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    ---------------------begin-----------------
    A constructor
    A copy constructor
    A deconstructor
    ---------------------end-----------------
    ---------------------begin-----------------
    A constructor
    A copy constructor
    A copy constructor
    A deconstructor
    A deconstructor
    ---------------------end-----------------
    ---------------------begin-----------------
    A constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A deconstructor
    A deconstructor
    A deconstructor
    ---------------------end-----------------
    ---------------------begin-----------------
    A constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A deconstructor
    A deconstructor
    A deconstructor
    A deconstructor
    ---------------------end-----------------
    ---------------------begin-----------------
    A constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A copy constructor
    A deconstructor
    A deconstructor
    A deconstructor
    A deconstructor
    A deconstructor
    ---------------------end-----------------
    A deconstructor
    A deconstructor
    A deconstructor
    A deconstructor
    A deconstructor
    说明:
    //造成以上的问题的主要原因是,vector存储是连续的,当存储数据的时候,要不断调整存储空间大小,所以就会不断的拷贝和析构;
    //解决上面的一个方法是,最开始就应该预留一个空间,调用reserve函数,这样就可以减少不必要的拷贝和析构;
    4)分配器的使用案例

    #include
    #include
    
    using namespace std;
    
    int main()
    {
    	std::list<int> list;
    	list.push_back(10);
    	list.push_back(20);
    	list.push_back(30);
    	list.push_back(40);
    	for (auto it = list.begin(); it != list.end(); it++)
    	{
    		int* ptr = &(*it);
    		printf("element address is: %p\r\n", ptr);
    	}
    
    	return 0;
    }
    //输出结果是(输出地址根本不联系!!!):
    element address is: 011DFEC0
    element address is: 011E0240
    element address is: 011E0278
    element address is: 011E0010
    结论:上述代码中,缺省的分配器根本没有用内存池技术,应该采用的是malloc这个技术!
    
    //使用分配器的方法:
    using namespace std;
    //不建议直接使用
    int main()
    {
    	std::allocator<int> allo;
    	int* ptr = allo.allocate(3);
    	*ptr = 1; ptr++;
    	*ptr = 2; ptr++;
    	*ptr = 3;
    	allo.deallocate(ptr,3);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    5)迭代器的使用

    迭代器是一个对象(确切的说,类似于一个指针的对象);
    迭代器和容器是紧密相关的。
    迭代器是分类标准:迭代器的移动特性和数据访问操作;
    输出迭代器,输入迭代器,前向迭代器,双向迭代器,随机访问迭代器
    output_iterator_tag 
    iterator、const_iterator、reverse_interator、const_reverse_interator
    
    有些模板类不提供迭代器,比如stack,deque,queue等;
    typename修饰模板类型
    typename iterator_traits<T>::iterator_category cagy; //"iterator_traits::iterator_category"是一个类型,typename是说明类型的
    #include
    #include
    
    using namespace std;
    
    template<typename T>
    void printMsg(const T& tmp)
    {
    	if (tmp.size() >= 2)
    	{
    		typename T::const_iterator iter(tmp.begin()); //错误提示:“const_iterator” : 类型 从属名称的使用必须以“typename”为前缀,所以必须添加为typename
    		int val = *iter;
    		cout << val << endl;
    	}
    }
    
    int main()
    {
    	std::vector<int> v{ 1,2,3,4 };
    	printMsg(v);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    6)STL算法概述
    算法就理解为函数,更确切的说是函数模板(全局函数/全局函数模板)
    算法的前两个参数,大多数是一个迭代器区间!
    前闭后开的好处:算法只要判断迭代器等于后边开区间,则表示迭代器结束;
    如果iterator_begin==iterator_end则代表为空区间;
    算法是搭配迭代器的使用的全局函数。算法跟容器没有毛关系,只跟迭代器有关。

    for_each(begin,end,可调用对象);
    仿写for_each遍历算法代码如下:
    void printMsg(int i)
    {
    	cout << i << endl;
    }
    template<typename inputIterator,typename Fun>
    void fun(inputIterator first, inputIterator end, Fun f)
    {
    	for (; first != end; first++)
    	{
    		f(*first);
    	}
    }
    int main()
    {
    	std::vector<int> vec{ 1,2,3,4,5 };
    	fun(vec.begin(), vec.end(), printMsg);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.1)sort的使用方法:

    sort中的仿函数调用对象
    class A
    {
    public:
    	bool operator()(int i,int y)
    	{
    		if (i > y)return true;
    		else return false;
    	}
    };
    
    int main()
    {
    	std::vector<int> vec{ 1,20,13,54,51 };
    	A a;
    	sort(vec.begin(), vec.end(),a);
    	for (auto it = vec.begin(); it != vec.end(); it++)
    	{
    		cout << *it << endl;
    	}
    	
    	return 0;
    }
    
    adjacent:[əˈdʒeɪsnt]  临近的; 
                                            饿滴   家
    ad是强调的作用,jac是ject的变体 记忆方法 ad  ja     cent  (我的家距离我近,回家可以吃饭)                                                                                                                                                                                                                                                                                            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    7)函数对象的学习

    函数对象也叫仿函数,是一个意思
    在stl中,函数对象一般都合算法配合使用,实现一些特定功能,主要服务于算法!!!
    标准模板库也给我们提供了一些函数对象,头文件包含<functional>,大概有十八个样子;
    plus<int>(); //对这句话的解释:plus是类模板,加上""才可以成为真正的类plus,再加上"()",生成一个临时对象,就是个可调用对象;
    使用方法如下:
    std::vector<int> vec{ 1,20,13,54,51 };
    sort(vec.begin(), vec.end(), greater<int>());
    for (auto it = vec.begin(); it != vec.end(); it++)
    {
    	cout << *it << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    学C语言的第一节课
    SSM框架(SpringBoot快速构建)
    C++入门-引用
    08.26 requests接口测试
    在不安全的集群上启用 Elasticsearch Xpack 安全性
    Pyspark的使用语法
    使用 Habana Gaudi2 加速视觉语言模型 BridgeTower
    Hadoop源码解析
    苹果Mac优化清理工具CleanMyMac X2023版本
    qt tcp 连接 秒断连
  • 原文地址:https://blog.csdn.net/qq_30143193/article/details/132599371