天天看點

順序容器:順序容器的操作

一、容器元素都是副本

在容器中添加元素時,系統是将元素值複制到容器裡。類似地,使用一段元素初始化新容器時,新容器存放的是原始元素的副本。

被複制的原始值與新容器中的元素各不相關,此後,容器内元素值發生變化時,被複制的原值不會受到影響,反之亦然。

void test_copy()
{
	int i = 10;

	std::vector<int> vec;
	vec.push_back(i);

	*(vec.begin()) = 9;
	std::cout << *(vec.begin()) << std::endl;	//9
	std::cout << i << std::endl;			//10,放進容器的值是副本,對容器的元素進行修改不影響原來的對象
}
           

二、任何對容器的增删操作都可能對已經定義的疊代器失效

void test_iterator()
{
	std::list<int> ls;
	ls.push_front(1);

	std::list<int>::iterator begin = ls.begin();
	std::cout << *begin << std::endl;	//1

	ls.push_front(2);	// 對于push_front操作隻适合list和deque容器
	std::cout << *begin << std::endl;	//1,begin依然指向原來的元素,并沒有指向新添加的元素2

	begin = ls.begin();	//
	std::cout << *begin << std::endl;	//2
}
           

三、測試insert操作

void printDeque( std::deque<int>::iterator &begin, std::deque<int>::iterator &end )
{
	while( begin != end )
	{
		std::cout << *begin << "_";
		++begin;
	}
	std::cout << std::endl;
}

// 測試insert操作
void test_insert()
{
	std::deque<int> de;
	for( unsigned int index = 0; index != 5; ++index )
	{
		de.push_front(index);
	}

	// 逆序疊代器
	std::deque<int>::reverse_iterator rit = de.rbegin(); // 指向容器的最後一位
	while( rit != de.rend() )	// 容器第一位的前一位
	{
		std::cout << *rit << std::endl;
		++rit;
	}

	std::deque<int>::iterator it;
	it = de.begin();
	++it;

	// 在指定的疊代器前面插入對象的副本
	de.insert(it,10);
	std::deque<int>::iterator begin = de.begin(), end = de.end();
	printDeque(begin, end);	// 4_10_3_2_1_0_

	// 在指定的疊代器前面連續插入n個對象的副本
	de.insert(it,3,20);
	std::deque<int>::iterator begin2 = de.begin(), end2 = de.end();
	printDeque(begin2,end2);// 4_10_20_20_20_3_2_1_0_

}

// 插入兩個疊代器标記範圍内的元素
void test_insert_2()
{
	std::deque<int> de;
	for( unsigned int index = 0; index != 5; ++index )
	{
		de.push_front(index);
	}

	int arr[] = { 10, 11, 12, 13, 14, 15};
	de.insert(de.begin(), arr, arr+sizeof(arr)/sizeof(int)/2);
	std::deque<int>::iterator begin = de.begin(), end = de.end();
	printDeque(begin, end);	// 10_11_12_4_3_2_1_0_
}


int main()
{
	test_insert_2();
	return 0;
}
           

四、放進容器的是對象的副本,取出容器的是對象的引用

// 從容器中傳回引用的方法:front()、back()、begin()、end()、at【隻對vec和deque有效】等
void test_inout()
{
	int i = 10;

	std::vector<int> vec;
	vec.push_back(i);

	i = 100;

	std::cout << i << std::endl;			// 100
	std::cout << vec.front() << std::endl;	// 10,修改i的值并沒有改變容器中的副本

	// 傳回的是引用,修改j的值等同于修改容器中對象,如果将j定義為:int j = vec.front(),
	// 則對j的修改不會對容器的對象起作用
	int &j = vec.front();
	j = 1000;
	std::cout << i << std::endl;			// 100
	std::cout << j << std::endl;			// 1000
	std::cout << vec.front() << std::endl;	// 1000,
}
           

五、關于resize操作

resize 操作可能會使疊代器失效。在 vector 或 deque 容器上做 resize 操作有可能會使其所有的疊代器都失效。

對于所有的容器類型,如果 resize 操作壓縮了容器,則指向已删除的元素疊代器失效。

/*
c.resize(n):
	調整容器 c 的長度大小,使其能容納 n 個元素,如果 n < c.size(),則删除多出來的元素;否則,添加采用值初始化的新元素
c.resize(n,t):
	調整容器 c 的長度大小,使其能容納 n 個元素。所有新添加的元素值都為 t
*/
void test_size_resize()
{
	std::vector<std::string> vec;
	if(vec.empty())
	{
		std::cout << vec.size() << std::endl;
	}
	std::cout << "容器能容納的最多元素個數為:" << vec.max_size() << std::endl;	// 1073741823

	vec.push_back("111");
	std::cout << vec.size() << std::endl;	// 1
	vec.resize(10);
	std::cout << "resize(10): " << vec.size() << std::endl;	// 10

	vec.resize(3, "aaa");
	std::cout << "resize(3): " << vec.size() << std::endl;	// 3
	for( unsigned int i = 0; i != vec.size(); ++i )
	{
		// 0:111  1:  2:
		// resize(n,t):隻有n大于原來的容器的容量時,新添加的元素才會初始化為t
		// 否則調用就調用resize(n)方法
		std::cout << i << ":" << vec[i] << std::endl;
	}

	vec.push_back("222");
	vec.push_back("333");
	std::cout << vec.size() << std::endl;	// 4
}
           

六、begin/end/front/back/at

// 如果容器為空或容器的大小為1,則front和back操作傳回的對象相等
void test_front_back()
{
	std::list<int> ls;
	int front = ls.front(), back = ls.back();
	if( front == back )
	{
		// 調用空容器的 front 或 back 函數,通常都會導緻程式出現嚴重的錯誤
		std::cout << "front element equals back element" << std::endl;	// ok
	}

	ls.push_back(1);
	front = ls.front();
	back = ls.back();
	if( front == back )
	{
		std::cout << "front element equals back element" << std::endl;	// ok
	}
}

/*
 在這段程式中,有兩個地方值得注意:
	1、end 疊代器指向容器的超出末端的下一位置,是以必須先對其減 1 才能擷取最後一個元素;
	2、在調用 front 或 back 函數之前,或者在對 begin 或end 傳回的疊代器進行解引用運算之前,必須保證ls容器非空,
	如果該list 容器為空,則 if 語句内所有的操作都沒有定義。
*/
void test_front_back_begin_end( std::list<int> &ls )
{
	if( !ls.empty() )
	{
		std::list<int>::reference begin = *ls.begin();
		std::list<int>::reference front = ls.front();

		if( begin == front )
		{
			std::cout << "ok" << std::endl;	// ok
		}

		std::list<int>::reference end = *--ls.end();
		std::list<int>::reference back = ls.back();
		if( end == back )
		{
			std::cout << "ok" << std::endl;	// ok
		}
	}
}

// 使用下标操作的兩種方式僅隻适合vector和deque,并不适合list
// 但是如果給出的下标無效,at 函數将會抛出 out_of_range異常
void test_at()
{
	std::vector<std::string> svec;
	std::cout << svec[0];
	std::cout << svec.at(0);
}