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是单向链表

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;
}

//输出结果
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;
}

---------------------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;
}

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;
}

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;
}

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  (我的家距离我近,回家可以吃饭)                                                                                                                                                                                                                                                                                            

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;
}

你可能感兴趣的:(c++,学习)