【STL】C++ STL 体系结构与内核分析源代码--侯捷


// author : Hou Jie (侯捷)
// date : 2015/10/28 
// compiler : DevC++ 5.11 (MinGW with GNU 4.9.9.2)
//
// 說明:這是侯捷 E-learning video "C++標準庫" 的實例程式.
// 該課程的所有測試都出現在此.
// 每一個小測試單元都被放進一個 namespace 中, 
// 如此保持各單元間最大的獨立性.
// 每個 namespace 上方皆有該單元相應的 #include <...> 
// 因此有可能整個程式重複含入 (included) 某些 headers. 
// 這無所謂,因為每個 standard headers 都有自我防衛機制,不讓自己被 included 二次.
//
// 本文件用到若干 C++ 2.0 New Features,所以你必須在你的集成環境 (IDE) 上設定 "C++11 on". 
// 如果你的編譯器報錯,應是因為我用到 (測試) GNU 標準庫的獨特 (非標準) 組件 (特別是 allocators),
// 將報錯語句改為註解 (comments) 即可通過編譯. 
 
using namespace std;
const long ASIZE = 500000L;
 
//----------------------------------------------------
#include <iostream>
#include <cstdio>  //snprintf()
#include <cstdlib> //RAND_MAX
#include <cstring> //strlen(), memcpy()
#include <string> 
using std::cin;
using std::cout;
using std::string;
 
//以下 MyString 是為了測試 containers with moveable elements 效果.  
class MyString {
public:
	static size_t DCtor;  	//累計 default-ctor 的呼叫次數 
	static size_t Ctor;  	//累計 ctor      的呼叫次數 
	static size_t CCtor;  	//累計 copy-ctor 的呼叫次數 
	static size_t CAsgn;  	//累計 copy-asgn 的呼叫次數 
	static size_t MCtor;  	//累計 move-ctor 的呼叫次數 
	static size_t MAsgn;  	//累計 move-asgn 的呼叫次數 		    
	static size_t Dtor;	//累計 dtor 的呼叫次數 
private:
	char* _data;
	size_t _len;
	void _init_data(const char *s) {
		_data = new char[_len + 1];
		memcpy(_data, s, _len);
		_data[_len] = '\0';
	}
public:
	//default ctor
	MyString() : _data(NULL), _len(0) { ++DCtor; }
 
	//ctor
	MyString(const char* p) : _len(strlen(p)) {
		++Ctor;
		_init_data(p);
	}
 
	// copy ctor
	MyString(const MyString& str) : _len(str._len) {
		++CCtor;
		_init_data(str._data); 	//COPY
	}
 
	//move ctor, with "noexcept"
	MyString(MyString&& str) noexcept : _data(str._data), _len(str._len) {
		++MCtor;
		str._len = 0;
		str._data = NULL;  	//避免 delete (in dtor) 
	}
 
	//copy assignment
	MyString& operator=(const MyString& str) {
		++CAsgn;
		if (this != &str) {
			if (_data) delete _data;
			_len = str._len;
			_init_data(str._data); 	//COPY! 
		}
		else {
			// Self Assignment, Nothing to do.   
		}
		return *this;
	}
 
	//move assignment
	MyString& operator=(MyString&& str) noexcept {
		++MAsgn;
		if (this != &str) {
			if (_data) delete _data;
			_len = str._len;
			_data = str._data;	//MOVE!
			str._len = 0;
			str._data = NULL; 	//避免 deleted in dtor 
		}
		return *this;
	}
 
	//dtor
	virtual ~MyString() {
		++Dtor;
		if (_data) {
			delete _data;
		}
	}
 
	bool
		operator<(const MyString& rhs) const	//為了讓 set 比較大小  
	{
		return std::string(this->_data) < std::string(rhs._data); 	//借用事實:string 已能比較大小. 
	}
	bool
		operator==(const MyString& rhs) const	//為了讓 set 判斷相等. 
	{
		return std::string(this->_data) == std::string(rhs._data); 	//借用事實:string 已能判斷相等. 
	}
 
	char* get() const { return _data; }
};
size_t MyString::DCtor = 0;
size_t MyString::Ctor = 0;
size_t MyString::CCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MCtor = 0;
size_t MyString::MAsgn = 0;
size_t MyString::Dtor = 0;
 
namespace std 	//必須放在 std 內 
{
	template<>
	struct hash<MyString> 	//這是為了 unordered containers 
	{
		size_t
			operator()(const MyString& s) const noexcept
		{
			return hash<string>()(string(s.get()));
		}
		//借用現有的 hash<string> (in ...\include\c++\bits\basic_string.h)
	};
}
//-----------------
//以下 MyStrNoMove 是為了測試 containers with no-moveable elements 效果.  
class MyStrNoMove {
public:
	static size_t DCtor;  	//累計 default-ctor 的呼叫次數 
	static size_t Ctor;  	//累計 ctor      的呼叫次數 
	static size_t CCtor;  	//累計 copy-ctor 的呼叫次數 
	static size_t CAsgn;  	//累計 copy-asgn 的呼叫次數 
	static size_t MCtor;  	//累計 move-ctor 的呼叫次數 
	static size_t MAsgn;  	//累計 move-asgn 的呼叫次數 		    
	static size_t Dtor;	    //累計 dtor 的呼叫次數 
private:
	char* _data;
	size_t _len;
	void _init_data(const char *s) {
		_data = new char[_len + 1];
		memcpy(_data, s, _len);
		_data[_len] = '\0';
	}
public:
	//default ctor
	MyStrNoMove() : _data(NULL), _len(0) { ++DCtor; _init_data("jjhou"); }
 
	//ctor
	MyStrNoMove(const char* p) : _len(strlen(p)) {
		++Ctor;  _init_data(p);
	}
 
	// copy ctor
	MyStrNoMove(const MyStrNoMove& str) : _len(str._len) {
		++CCtor;
		_init_data(str._data); 	//COPY
	}
 
	//copy assignment
	MyStrNoMove& operator=(const MyStrNoMove& str) {
		++CAsgn;
 
		if (this != &str) {
			if (_data) delete _data;
			_len = str._len;
			_init_data(str._data); 	//COPY! 
		}
		else {
			// Self Assignment, Nothing to do.   
		}
		return *this;
	}
 
	//dtor
	virtual ~MyStrNoMove() {
		++Dtor;
		if (_data) {
			delete _data;
		}
	}
 
	bool
		operator<(const MyStrNoMove& rhs) const		//為了讓 set 比較大小 
	{
		return string(this->_data) < string(rhs._data);  //借用事實:string 已能比較大小. 
	}
 
	bool
		operator==(const MyStrNoMove& rhs) const	//為了讓 set 判斷相等. 
	{
		return string(this->_data) == string(rhs._data);  //借用事實:string 已能判斷相等. 
	}
 
	char* get() const { return _data; }
};
size_t MyStrNoMove::DCtor = 0;
size_t MyStrNoMove::Ctor = 0;
size_t MyStrNoMove::CCtor = 0;
size_t MyStrNoMove::CAsgn = 0;
size_t MyStrNoMove::MCtor = 0;
size_t MyStrNoMove::MAsgn = 0;
size_t MyStrNoMove::Dtor = 0;
 
namespace std 	//必須放在 std 內 
{
	template<>
	struct hash<MyStrNoMove> 	//這是為了 unordered containers 
	{
		size_t
			operator()(const MyStrNoMove& s) const noexcept
		{
			return hash<string>()(string(s.get()));
		}
		//借用現有的 hash<string> (in ...\4.9.2\include\c++\bits\basic_string.h)
	};
}
 
//----------------------------------------------------
#include <iostream>
#include <cstdio>  //snprintf()
#include <cstdlib> //RAND_MAX
#include <string> 
#include <algorithm> 
#include <list> 
#include <forward_list> 
using std::cin;
using std::cout;
using std::string;
using std::max;
using std::min;
 
namespace jj00
{
 
	bool strLonger(const string& s1, const string& s2) {
		return s1.size() < s2.size();
	}
 
	void test_misc()
	{
		cout << "\ntest_misc().......... \n";
 
		//以下這些是標準庫的眾多容器的 max_size() 計算方式.  
		cout << size_t(-1) << endl;					         	//4294967295
		cout << size_t(-1) / sizeof(long) << endl;		     	//1073741823
		cout << size_t(-1) / sizeof(string) << endl;	         	//1073741823
		//cout << size_t(-1) / sizeof(_List_node<string>) << endl; 	//357913941
		//cout << size_t(-1) / sizeof(_Fwd_list_node<string>) << endl; //536870911
		cout << "RAND_MAX= " << RAND_MAX << endl;	//32767
 
		cout << min({ 2,5,8,9,45,0,81 }) << endl;  //0
		cout << max({ 2,5,8,9,45,0,81 }) << endl;  //81
		//vector<int> v={2,5,8,9,45,0,81};
 
		cout << "max of     zoo and hello : "
			<< max(string("zoo"), string("hello")) << endl;              //zoo
		cout << "longest of zoo and hello : "
			<< max(string("zoo"), string("hello"), strLonger) << endl;   //hello    
 
		cout << hash<MyString>()(MyString("Ace")) << endl;		//1765813650
		cout << hash<MyString>()(MyString("Stacy")) << endl;	//2790324277
		cout << "MyString(zoo) < MyString(hello) ==> " << (MyString("zoo") < MyString("hello")) << endl;	//0
		cout << "MyString(zoo) == MyString(hello) ==> " << (MyString("zoo") == MyString("hello")) << endl;	//0	  
		cout << "MyStrNoMove(zoo) < MyStrNoMove(hello) ==> " << (MyStrNoMove("zoo") < MyStrNoMove("hello")) << endl;	 //0
		cout << "MyStrNoMove(zoo) == MyStrNoMove(hello) ==> " << (MyStrNoMove("zoo") == MyStrNoMove("hello")) << endl;	 //0
		//以上建構了 6 個 MyString objects 和 4 個 MyStrNoMove objects,都是暫時生命.    
	}
}
//--------------------------------------------------
#include <typeinfo>  //typeid()
template<typename T>
void output_static_data(const T& myStr)
{
	cout << typeid(myStr).name() << " -- " << endl;
	cout << " CCtor=" << T::CCtor
		<< " MCtor=" << T::MCtor
		<< " CAsgn=" << T::CAsgn
		<< " MAsgn=" << T::MAsgn
		<< " Dtor=" << T::Dtor
		<< " Ctor=" << T::Ctor
		<< " DCtor=" << T::DCtor
		<< endl;
}
 
#include <ctime>  //clock_t, clock()
template<typename M, typename NM>
void test_moveable(M c1, NM c2, long& value)
{
	char buf[10];
 
	//測試 move 
	cout << "\n\ntest, with moveable elements" << endl;
	typedef typename iterator_traits<typename M::iterator>::value_type  V1type;
	clock_t timeStart = clock();
	for (long i = 0; i < value; ++i)
	{
		snprintf(buf, 10, "%d", rand());
		auto ite = c1.end();
		c1.insert(ite, V1type(buf));
	}
	cout << "construction, milli-seconds : " << (clock() - timeStart) << endl;
	cout << "size()= " << c1.size() << endl;
	output_static_data(*(c1.begin()));
 
	timeStart = clock();
	M c11(c1);
	cout << "copy, milli-seconds : " << (clock() - timeStart) << endl;
 
	timeStart = clock();
	M c12(std::move(c1));
	cout << "move copy, milli-seconds : " << (clock() - timeStart) << endl;
 
	timeStart = clock();
	c11.swap(c12);
	cout << "swap, milli-seconds : " << (clock() - timeStart) << endl;
 
 
 
	//測試 non-moveable 	
	cout << "\n\ntest, with non-moveable elements" << endl;
	typedef typename iterator_traits<typename NM::iterator>::value_type  V2type;
	timeStart = clock();
	for (long i = 0; i < value; ++i)
	{
		snprintf(buf, 10, "%d", rand());
		auto ite = c2.end();
		c2.insert(ite, V2type(buf));
	}
 
	cout << "construction, milli-seconds : " << (clock() - timeStart) << endl;
	cout << "size()= " << c2.size() << endl;
	output_static_data(*(c2.begin()));
 
	timeStart = clock();
	NM c21(c2);
	cout << "copy, milli-seconds : " << (clock() - timeStart) << endl;
 
	timeStart = clock();
	NM c22(std::move(c2));
	cout << "move copy, milli-seconds : " << (clock() - timeStart) << endl;
 
	timeStart = clock();
	c21.swap(c22);
	cout << "swap, milli-seconds : " << (clock() - timeStart) << endl;
}
//-----------------
long get_a_target_long()
{
	long target = 0;
 
	cout << "target (0~" << RAND_MAX << "): ";
	cin >> target;
	return target;
}
 
string get_a_target_string()
{
	long target = 0;
	char buf[10];
 
	cout << "target (0~" << RAND_MAX << "): ";
	cin >> target;
	snprintf(buf, 10, "%d", target);
	return string(buf);
}
 
int compareLongs(const void* a, const void* b)
{
	return (*(long*)a - *(long*)b);
}
 
int compareStrings(const void* a, const void* b)
{
	if (*(string*)a > *(string*)b)
		return 1;
	else if (*(string*)a < *(string*)b)
		return -1;
	else
		return 0;
}
//---------------------------------------------------
#include <array>
#include <iostream>
#include <ctime> 
#include <cstdlib> //qsort, bsearch, NULL
 
namespace jj01
{
	void test_array()
	{
		cout << "\ntest_array().......... \n";
 
		array<long, ASIZE> c;
 
		clock_t timeStart = clock();
		for (long i = 0; i < ASIZE; ++i) {
			c[i] = rand();
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;	//
		cout << "array.size()= " << c.size() << endl;
		cout << "array.front()= " << c.front() << endl;
		cout << "array.back()= " << c.back() << endl;
		cout << "array.data()= " << c.data() << endl;
 
		long target = get_a_target_long();
 
		timeStart = clock();
		::qsort(c.data(), ASIZE, sizeof(long), compareLongs);
		//sort(c.begin(), c.end());
		cout << "qsort(), milli-seconds : " << (clock() - timeStart) << endl;	//  
		timeStart = clock();
		long* pItem = (long*)::bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
		cout << "bsearch(), milli-seconds : " << (clock() - timeStart) << endl;	//    
		if (pItem != NULL)
			cout << "found, " << *pItem << endl;
		else
			cout << "not found! " << endl;
	}
}
//---------------------------------------------------
#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
#include <algorithm> 	//sort()
namespace jj02
{
	void test_vector(long& value)
	{
		cout << "\ntest_vector().......... \n";
 
		vector<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push_back(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				//曾經最高 i=58389486 then std::bad_alloc
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "vector.max_size()= " << c.max_size() << endl;	//1073747823
		cout << "vector.size()= " << c.size() << endl;
		cout << "vector.front()= " << c.front() << endl;
		cout << "vector.back()= " << c.back() << endl;
		cout << "vector.data()= " << c.data() << endl;
		cout << "vector.capacity()= " << c.capacity() << endl << endl;
 
 
		string target = get_a_target_string();
		{
			timeStart = clock();
			auto pItem = find(c.begin(), c.end(), target);
			cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
 
			if (pItem != c.end())
				cout << "found, " << *pItem << endl << endl;
			else
				cout << "not found! " << endl << endl;
		}
 
		{
			timeStart = clock();
			//sort(c.begin(), c.end());
			::qsort(c.data(), c.size(), sizeof(string), compareStrings);
			cout << "qsort(), milli-seconds : " << (clock() - timeStart) << endl;
 
			timeStart = clock();
			string* pItem = (string*)::bsearch(&target, (c.data()),
				c.size(), sizeof(string), compareStrings);
			cout << "bsearch(), milli-seconds : " << (clock() - timeStart) << endl;
 
			if (pItem != NULL)
				cout << "found, " << *pItem << endl << endl;
			else
				cout << "not found! " << endl << endl;
		}
 
		c.clear();
		test_moveable(vector<MyString>(), vector<MyStrNoMove>(), value);
	}
}
//---------------------------------------------------
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime> 
namespace jj03
{
	void test_list(long& value)
	{
		cout << "\ntest_list().......... \n";
 
		list<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push_back(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "list.size()= " << c.size() << endl;
		cout << "list.max_size()= " << c.max_size() << endl;    //357913941
		cout << "list.front()= " << c.front() << endl;
		cout << "list.back()= " << c.back() << endl;
 
		string target = get_a_target_string();
		timeStart = clock();
		auto pItem = find(c.begin(), c.end(), target);
		cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
 
		if (pItem != c.end())
			cout << "found, " << *pItem << endl;
		else
			cout << "not found! " << endl;
 
		timeStart = clock();
		c.sort();
		cout << "c.sort(), milli-seconds : " << (clock() - timeStart) << endl;
 
 
 
		c.clear();
		test_moveable(list<MyString>(), list<MyStrNoMove>(), value);
	}
}
//---------------------------------------------------
#include <forward_list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj04
{
	void test_forward_list(long& value)
	{
		cout << "\ntest_forward_list().......... \n";
 
		forward_list<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push_front(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "forward_list.max_size()= " << c.max_size() << endl;  //536870911
		cout << "forward_list.front()= " << c.front() << endl;
 
 
		string target = get_a_target_string();
		timeStart = clock();
		auto pItem = find(c.begin(), c.end(), target);
		cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
 
		if (pItem != c.end())
			cout << "found, " << *pItem << endl;
		else
			cout << "not found! " << endl;
 
		timeStart = clock();
		c.sort();
		cout << "c.sort(), milli-seconds : " << (clock() - timeStart) << endl;
 
		c.clear();
	}
}
//---------------------------------------------------
#include <deque>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj05
{
	void test_deque(long& value)
	{
		cout << "\ntest_deque().......... \n";
 
		deque<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push_back(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "deque.size()= " << c.size() << endl;
		cout << "deque.front()= " << c.front() << endl;
		cout << "deque.back()= " << c.back() << endl;
		cout << "deque.max_size()= " << c.max_size() << endl;	//1073741821	
 
		string target = get_a_target_string();
		timeStart = clock();
		auto pItem = find(c.begin(), c.end(), target);
		cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
 
		if (pItem != c.end())
			cout << "found, " << *pItem << endl;
		else
			cout << "not found! " << endl;
 
		timeStart = clock();
		sort(c.begin(), c.end());
		cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
 
		c.clear();
		test_moveable(deque<MyString>(), deque<MyStrNoMove>(), value);
	}
}
//---------------------------------------------------
#include <set>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj06
{
	void test_multiset(long& value)
	{
		cout << "\ntest_multiset().......... \n";
 
		multiset<string> c;
		char buf[10];
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.insert(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "multiset.size()= " << c.size() << endl;
		cout << "multiset.max_size()= " << c.max_size() << endl;	//214748364
 
		string target = get_a_target_string();
		{
			timeStart = clock();
			auto pItem = find(c.begin(), c.end(), target);	//比 c.find(...) 慢很多	
			cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		{
			timeStart = clock();
			auto pItem = c.find(target);		//比 std::find(...) 快很多							
			cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		c.clear();
		test_moveable(multiset<MyString>(), multiset<MyStrNoMove>(), value);
	}
}
//---------------------------------------------------
#include <map>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj07
{
	void test_multimap(long& value)
	{
		cout << "\ntest_multimap().......... \n";
 
		multimap<long, string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				//multimap 不可使用 [] 做 insertion 
				c.insert(pair<long, string>(i, buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "multimap.size()= " << c.size() << endl;
		cout << "multimap.max_size()= " << c.max_size() << endl;	//178956970	
 
		long target = get_a_target_long();
		timeStart = clock();
		auto pItem = c.find(target);
		cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
		if (pItem != c.end())
			cout << "found, value=" << (*pItem).second << endl;
		else
			cout << "not found! " << endl;
 
		c.clear();
	}
}
//---------------------------------------------------
#include <unordered_set>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj08
{
	void test_unordered_multiset(long& value)
	{
		cout << "\ntest_unordered_multiset().......... \n";
 
		unordered_multiset<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.insert(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "unordered_multiset.size()= " << c.size() << endl;
		cout << "unordered_multiset.max_size()= " << c.max_size() << endl;	//357913941
		cout << "unordered_multiset.bucket_count()= " << c.bucket_count() << endl;
		cout << "unordered_multiset.load_factor()= " << c.load_factor() << endl;
		cout << "unordered_multiset.max_load_factor()= " << c.max_load_factor() << endl;
		cout << "unordered_multiset.max_bucket_count()= " << c.max_bucket_count() << endl;
		for (unsigned i = 0; i < 20; ++i) {
			cout << "bucket #" << i << " has " << c.bucket_size(i) << " elements.\n";
		}
 
		string target = get_a_target_string();
		{
			timeStart = clock();
			auto pItem = find(c.begin(), c.end(), target);	//比 c.find(...) 慢很多	
			cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		{
			timeStart = clock();
			auto pItem = c.find(target);		//比 std::find(...) 快很多							
			cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		c.clear();
		test_moveable(unordered_multiset<MyString>(), unordered_multiset<MyStrNoMove>(), value);
	}
}
//---------------------------------------------------
#include <unordered_map>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj09
{
	void test_unordered_multimap(long& value)
	{
		cout << "\ntest_unordered_multimap().......... \n";
 
		unordered_multimap<long, string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				//multimap 不可使用 [] 進行 insertion 
				c.insert(pair<long, string>(i, buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "unordered_multimap.size()= " << c.size() << endl;
		cout << "unordered_multimap.max_size()= " << c.max_size() << endl;	//357913941	
 
		long target = get_a_target_long();
		timeStart = clock();
		auto pItem = c.find(target);
		cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
		if (pItem != c.end())
			cout << "found, value=" << (*pItem).second << endl;
		else
			cout << "not found! " << endl;
	}
}
//---------------------------------------------------
#include <list>
	//注意, 上一行並沒有引發警告訊息如 #include <ext\hash_set> 所引發者: 
	//...\4.9.2\include\c++\backward\backward_warning.h	
	//[Warning] ...
 
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
//namespace jj10
//{
//	void test_slist(long& value)
//	{
//		cout << "\ntest_slist().......... \n";
//
//		__gnu_cxx::sList<string> c;
//		char buf[10];
//
//		clock_t timeStart = clock();
//		for (long i = 0; i < value; ++i)
//		{
//			try {
//				snprintf(buf, 10, "%d", rand());
//				c.push_front(string(buf));
//			}
//			catch (exception& p) {
//				cout << "i=" << i << " " << p.what() << endl;
//				abort();
//			}
//		}
//		cout << "milli-seconds : " << (clock() - timeStart) << endl;
//	}
//}
//---------------------------------------------------
/*
以下測試 hash_multiset, hash_multimap 過程中遇到阻礙:
headers <hash_set> 和 <hash_map> 各有兩個,
分別在 ...\4.9.2\include\c++\backward 和 ...\4.9.2\include\c++\ext,
不知要用哪一組!
用 <ext\...> 那一組會有問題
   ...\4.9.2\include\c++\backward\hashtable.h
   [Error] no match for call to '(const hasher {aka const __gnu_cxx::hash<std::basic_string<char> >}) (const key_type&)'
用 <backward\...> 那一組有相同的問題.
so, 放棄測試 (no insertion or push_back or ...).
*/
 
#include <unordered_set>		
	
//...\4.9.2\include\c++\backward\backward_warning.h	
//[Warning] #warning This file includes at least one deprecated or antiquated header 
//which may be removed without further notice at a future date. 
//Please use a non-deprecated interface with equivalent functionality instead. 
//For a listing of replacement headers and interfaces, consult the file backward_warning.h. 
//To disable this warning use -Wno-deprecated. [-Wcpp]
 
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj11
{
	void test_hash_multiset(long& value)
	{
		cout << "\ntest_hash_multiset().......... \n";
 
		unordered_multiset<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				//! c.insert(string(buf));     		
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
	}
}
//---------------------------------------------------
#include <unordered_map>
	//...\4.9.2\include\c++\backward\backward_warning.h	
	//[Warning] #warning This file ... (如上個函數所言)
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj12
{
	void test_hash_multimap(long& value)
	{
		cout << "\ntest_hash_multimap().......... \n";
 
		unordered_map<long, string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				//c.insert(...   		
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
 
		timeStart = clock();
		//! auto ite = c.find(...
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
	}
}
//---------------------------------------------------
#include <set>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj13
{
	void test_set(long& value)
	{
		cout << "\ntest_set().......... \n";
 
		set<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.insert(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "set.size()= " << c.size() << endl;
		cout << "set.max_size()= " << c.max_size() << endl;	   //214748364
 
		string target = get_a_target_string();
		{
			timeStart = clock();
			auto pItem = find(c.begin(), c.end(), target);	//比 c.find(...) 慢很多	
			cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		{
			timeStart = clock();
			auto pItem = c.find(target);		//比 std::find(...) 快很多							
			cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
	}
}
//---------------------------------------------------
#include <map>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj14
{
	void test_map(long& value)
	{
		cout << "\ntest_map().......... \n";
 
		map<long, string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c[i] = string(buf);
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl; 
		cout << "map.size()= " << c.size() << endl;
		cout << "map.max_size()= " << c.max_size() << endl;		//178956970
 
		long target = get_a_target_long();
		timeStart = clock();
		auto pItem = c.find(target);
		cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
		if (pItem != c.end())
			cout << "found, value=" << (*pItem).second << endl;
		else
			cout << "not found! " << endl;
 
		c.clear();
	}
}
//---------------------------------------------------
#include <unordered_set>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj15
{
	void test_unordered_set(long& value)
	{
		cout << "\ntest_unordered_set().......... \n";
 
		unordered_set<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.insert(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "unordered_set.size()= " << c.size() << endl;
		cout << "unordered_set.max_size()= " << c.max_size() << endl;  //357913941
		cout << "unordered_set.bucket_count()= " << c.bucket_count() << endl;
		cout << "unordered_set.load_factor()= " << c.load_factor() << endl;
		cout << "unordered_set.max_load_factor()= " << c.max_load_factor() << endl;
		cout << "unordered_set.max_bucket_count()= " << c.max_bucket_count() << endl;
		for (unsigned i = 0; i < 20; ++i) {
			cout << "bucket #" << i << " has " << c.bucket_size(i) << " elements.\n";
		}
 
		string target = get_a_target_string();
		{
			timeStart = clock();
			auto pItem = find(c.begin(), c.end(), target);	//比 c.find(...) 慢很多	
			cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
 
		{
			timeStart = clock();
			auto pItem = c.find(target);		//比 std::find(...) 快很多							
			cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
			if (pItem != c.end())
				cout << "found, " << *pItem << endl;
			else
				cout << "not found! " << endl;
		}
	}
}
//---------------------------------------------------
#include <unordered_map>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj16
{
	void test_unordered_map(long& value)
	{
		cout << "\ntest_unordered_map().......... \n";
 
		unordered_map<long, string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c[i] = string(buf);
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "unordered_map.size()= " << c.size() << endl;	//357913941
		cout << "unordered_map.max_size()= " << c.max_size() << endl;
 
		long target = get_a_target_long();
		timeStart = clock();
		//! auto pItem = find(c.begin(), c.end(), target);	//map 不適用 std::find() 			
		auto pItem = c.find(target);
 
		cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
		if (pItem != c.end())
			cout << "found, value=" << (*pItem).second << endl;
		else
			cout << "not found! " << endl;
	}
}
//---------------------------------------------------
#include <stack>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj17
{
	void test_stack(long& value)
	{
		cout << "\ntest_stack().......... \n";
 
		stack<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "stack.size()= " << c.size() << endl;
		cout << "stack.top()= " << c.top() << endl;
		c.pop();
		cout << "stack.size()= " << c.size() << endl;
		cout << "stack.top()= " << c.top() << endl;
 
 
		{
			stack<string, list<string>> c;		//以 list 為底層 
			for (long i = 0; i < 10; ++i) {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			cout << "stack.size()= " << c.size() << endl;
			cout << "stack.top()= " << c.top() << endl;
			c.pop();
			cout << "stack.size()= " << c.size() << endl;
			cout << "stack.top()= " << c.top() << endl;
		}
 
		{
			stack<string, vector<string>> c;	//以 vector 為底層 
			for (long i = 0; i < 10; ++i) {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			cout << "stack.size()= " << c.size() << endl;
			cout << "stack.top()= " << c.top() << endl;
			c.pop();
			cout << "stack.size()= " << c.size() << endl;
			cout << "stack.top()= " << c.top() << endl;
		}
 
		{
			stack<string, set<string>> c;	//以 set 為底層 
			/*!
				for(long i=0; i< 10; ++i) {
						snprintf(buf, 10, "%d", rand());
						c.push(string(buf));
				}
				cout << "stack.size()= " << c.size() << endl;
				cout << "stack.top()= " << c.top() << endl;
				c.pop();
				cout << "stack.size()= " << c.size() << endl;
				cout << "stack.top()= " << c.top() << endl;
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'back'
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_back'
			*/
		}
 
		//!stack<string, map(string>> c5;	以 map 為底層, [Error] template argument 2 is invalid
		//!stack<string>::iterator ite1;  	//[Error] 'iterator' is not a member of 'std::stack<std::basic_string<char> >'
 
	}
}
//---------------------------------------------------
#include <queue>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
namespace jj18
{
	void test_queue(long& value)
	{
		cout << "\ntest_queue().......... \n";
 
		queue<string> c;
		char buf[10];
 
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "milli-seconds : " << (clock() - timeStart) << endl;
		cout << "queue.size()= " << c.size() << endl;
		cout << "queue.front()= " << c.front() << endl;
		cout << "queue.back()= " << c.back() << endl;
		c.pop();
		cout << "queue.size()= " << c.size() << endl;
		cout << "queue.front()= " << c.front() << endl;
		cout << "queue.back()= " << c.back() << endl;
 
 
		{
			queue<string, list<string>> c;		//以 list 為底層 
			for (long i = 0; i < 10; ++i) {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			cout << "queue.size()= " << c.size() << endl;
			cout << "queue.front()= " << c.front() << endl;
			cout << "queue.back()= " << c.back() << endl;
			c.pop();
			cout << "queue.size()= " << c.size() << endl;
			cout << "queue.front()= " << c.front() << endl;
			cout << "queue.back()= " << c.back() << endl;
		}
 
		{
			queue<string, vector<string>> c;	//以 vector 為底層 
			for (long i = 0; i < 10; ++i) {
				snprintf(buf, 10, "%d", rand());
				c.push(string(buf));
			}
			cout << "queue.size()= " << c.size() << endl;
			cout << "queue.front()= " << c.front() << endl;
			cout << "queue.back()= " << c.back() << endl;
			//!c.pop();  //[Error] 'class std::vector<std::basic_string<char> >' has no member named 'pop_front'
			cout << "queue.size()= " << c.size() << endl;
			cout << "queue.front()= " << c.front() << endl;
			cout << "queue.back()= " << c.back() << endl;
		}
 
		{
			queue<string, set<string>> c;		//以 set 為底層 
			/*!
				for(long i=0; i< 10; ++i) {
						snprintf(buf, 10, "%d", rand());
						c.push(string(buf));
				}
				cout << "queue.size()= " << c.size() << endl;
				cout << "queue.front()= " << c.front() << endl;
				cout << "queue.back()= " << c.back() << endl;
				c.pop();
				cout << "queue.size()= " << c.size() << endl;
				cout << "queue.front()= " << c.front() << endl;
				cout << "queue.back()= " << c.back() << endl;
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'push_back'
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'front'
			//[Error] 'class std::set<std::basic_string<char> >' has no member named 'pop_front'
			*/
		}
 
		//! queue<string, map<string>> c5;	//以 map 為底層, [Error] template argument 2 is invalid
		//! queue<string>::iterator ite1;  	//[Error] 'iterator' is not a member of 'std::queue<std::basic_string<char> >'	
	}
}
//---------------------------------------------------
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> 		//abort()
#include <cstdio>  		//snprintf()
#include <algorithm> 	//find()
#include <iostream>
#include <ctime> 
 
#include <cstddef>
#include <memory>	//內含 std::allocator  
	//欲使用 std::allocator 以外的 allocator, 得自行 #include <ext\...> 
#ifdef __GNUC__		
#include <ext\array_allocator.h>
#include <ext\mt_allocator.h>
#include <ext\debug_allocator.h>
#include <ext\pool_allocator.h>
#include <ext\bitmap_allocator.h>
#include <ext\malloc_allocator.h>
#include <ext\new_allocator.h>  
#endif
 
namespace jj20
{
	//pass A object to function template impl(),
	//而 A 本身是個 class template, 帶有 type parameter T,  
	//那麼有無可能在 impl() 中抓出 T, 創建一個 list<T, A<T>> object? 
	//以下先暫時迴避上述疑問.
 
	void test_list_with_special_allocator()
	{
#ifdef __GNUC__	
		cout << "\ntest_list_with_special_allocator().......... \n";
 
		//不能在 switch case 中宣告,只好下面這樣. 				//1000000次 
		list<string, allocator<string>> c1;						//3140
		list<string, __gnu_cxx::malloc_allocator<string>> c2;  	//3110
		list<string, __gnu_cxx::new_allocator<string>> c3; 		//3156
		list<string, __gnu_cxx::__pool_alloc<string>> c4;  		//4922
		list<string, __gnu_cxx::__mt_alloc<string>> c5; 		//3297
		list<string, __gnu_cxx::bitmap_allocator<string>> c6;  	//4781 														
 
		int choice;
		long value;
 
		cout << "select: "
			<< " (1) std::allocator "
			<< " (2) malloc_allocator "
			<< " (3) new_allocator "
			<< " (4) __pool_alloc "
			<< " (5) __mt_alloc "
			<< " (6) bitmap_allocator ";
 
		cin >> choice;
		if (choice != 0) {
			cout << "how many elements: ";
			cin >> value;
		}
 
		char buf[10];
		clock_t timeStart = clock();
		for (long i = 0; i < value; ++i)
		{
			try {
				snprintf(buf, 10, "%d", i);
				switch (choice)
				{
				case 1: 	c1.push_back(string(buf));
					break;
				case 2: 	c2.push_back(string(buf));
					break;
				case 3: 	c3.push_back(string(buf));
					break;
				case 4: 	c4.push_back(string(buf));
					break;
				case 5: 	c5.push_back(string(buf));
					break;
				case 6: 	c6.push_back(string(buf));
					break;
				default:
					break;
				}
			}
			catch (exception& p) {
				cout << "i=" << i << " " << p.what() << endl;
				abort();
			}
		}
		cout << "a lot of push_back(), milli-seconds : " << (clock() - timeStart) << endl;
 
 
		//test all allocators' allocate() & deallocate();
		int* p;
		allocator<int> alloc1;
		p = alloc1.allocate(1);
		alloc1.deallocate(p, 1);
 
		__gnu_cxx::malloc_allocator<int> alloc2;
		p = alloc2.allocate(1);
		alloc2.deallocate(p, 1);
 
		__gnu_cxx::new_allocator<int> alloc3;
		p = alloc3.allocate(1);
		alloc3.deallocate(p, 1);
 
		__gnu_cxx::__pool_alloc<int> alloc4;
		p = alloc4.allocate(2);
		alloc4.deallocate(p, 2); 	//我刻意令參數為 2, 但這有何意義!! 一次要 2 個 ints? 
 
		__gnu_cxx::__mt_alloc<int> alloc5;
		p = alloc5.allocate(1);
		alloc5.deallocate(p, 1);
 
		__gnu_cxx::bitmap_allocator<int> alloc6;
		p = alloc6.allocate(3);
		alloc6.deallocate(p, 3);  	//我刻意令參數為 3, 但這有何意義!! 一次要 3 個 ints? 
#endif 			
	}
}
//---------------------------------------------------
#include <list>
#include <string>
#include <iostream>
 
#include <memory>		//內含 std::allocator  
//#include <bits\stl_tree.h>  //內含 _RB_tree (不需此行, 因為它被含入於 <set> and <map>)
 
//欲使用 std::allocator 以外的 allocator, 得自行 #include <ext\...> 
//#include <ext\array_allocator.h>
//#include <ext\mt_allocator.h>
//#include <ext\debug_allocator.h>
//#include <ext\pool_allocator.h>
//#include <ext\bitmap_allocator.h>
//#include <ext\malloc_allocator.h>
//#include <ext\new_allocator.h>  
 
namespace jj25
{
	void test_components_sizeof()
	{
		cout << "\ntest_components_size().......... \n";
 
		//containers
		cout << "sizeof(array<int,100>)= " << sizeof(array<int, 100>) << endl;		//400
		cout << "sizeof(vector<int>)= " << sizeof(vector<int>) << endl;				//12
		cout << "sizeof(list<int>)= " << sizeof(list<int>) << endl;					//8
		cout << "sizeof(forward_list<int>)= " << sizeof(forward_list<int>) << endl;	//4
		cout << "sizeof(deque<int>)= " << sizeof(deque<int>) << endl;				//40
		cout << "sizeof(stack<int>)= " << sizeof(stack<int>) << endl;				//40
		cout << "sizeof(queue<int>)= " << sizeof(queue<int>) << endl;				//40
		cout << "sizeof(set<int>)= " << sizeof(set<int>) << endl;					//24
		cout << "sizeof(map<int,int>)= " << sizeof(map<int, int>) << endl;			//24
		cout << "sizeof(multiset<int>)= " << sizeof(multiset<int>) << endl;			//24
		cout << "sizeof(multimap<int,int>)= " << sizeof(multimap<int, int>) << endl;	//24
		cout << "sizeof(unordered_set<int>)= " << sizeof(unordered_set<int>) << endl;					//28
		cout << "sizeof(unordered_map<int,int>)= " << sizeof(unordered_map<int, int>) << endl;			//28	
		cout << "sizeof(unordered_multiset<int>)= " << sizeof(unordered_multiset<int>) << endl;			//28
		cout << "sizeof(unordered_multimap<int,int>)= " << sizeof(unordered_multimap<int, int>) << endl;	//28
		//cout << "sizeof(_Rb_tree<...>)= " << sizeof(_Rb_tree<int, int, _Identity<int>, less<int>>) << endl; //24
 
		//iterators
		cout << "sizeof(array<int,100>::iterator)= " << sizeof(array<int, 100>::iterator) << endl;		//4
		cout << "sizeof(vector<int>::iterator)= " << sizeof(vector<int>::iterator) << endl;				//4
		cout << "sizeof(list<int>::iterator)= " << sizeof(list<int>::iterator) << endl;					//4
		cout << "sizeof(forward_list<int>::iterator)= " << sizeof(forward_list<int>::iterator) << endl; //4
		cout << "sizeof(deque<int>::iterator)= " << sizeof(deque<int>::iterator) << endl;				//16
		//! cout << "sizeof(stack<int>::iterator)= " << sizeof(stack<int>::iterator) << endl;	//[Error] 'iterator' is not a member of 'std::stack<int>'		
		//! cout << "sizeof(queue<int>::iterator)= " << sizeof(queue<int>::iterator) << endl;	//[Error] 'iterator' is not a member of 'std::queue<int>			
		cout << "sizeof(set<int>::iterator)= " << sizeof(set<int>::iterator) << endl;					//4
		cout << "sizeof(map<int,int>::iterator)= " << sizeof(map<int, int>::iterator) << endl;			//4
		cout << "sizeof(multiset<int>::iterator)= " << sizeof(multiset<int>::iterator) << endl;			//4
		cout << "sizeof(multimap<int,int>::iterator)= " << sizeof(multimap<int, int>::iterator) << endl;	//4
		cout << "sizeof(unordered_set<int>::iterator)= " << sizeof(unordered_set<int>::iterator) << endl;	//4	
		cout << "sizeof(unordered_map<int,int>::iterator)= " << sizeof(unordered_map<int, int>::iterator) << endl;	//4	
		cout << "sizeof(unordered_multiset<int>::iterator)= " << sizeof(unordered_multiset<int>::iterator) << endl;	//4
		cout << "sizeof(unordered_multimap<int,int>::iterator)= " << sizeof(unordered_multimap<int, int>::iterator) << endl;	//4										
		//cout << "sizeof(_Rb_tree<...>::iterator)= " << sizeof(_Rb_tree<int, int, _Identity<int>, less<int>>::iterator) << endl; //4
 
		//allocators
		cout << "sizeof(      std::allocator<string>)=" << sizeof(std::allocator<string>) << endl;						//1 (理論值 0)
		//cout << "sizeof(__gnu_cxx::malloc_allocator<string>)= " << sizeof(__gnu_cxx::malloc_allocator<string>) << endl; //1 (理論值 0) 
		//cout << "sizeof(__gnu_cxx::new_allocator<string>)= " << sizeof(__gnu_cxx::new_allocator<string>) << endl; 	    //1 (理論值 0)
		//cout << "sizeof(__gnu_cxx::__pool_alloc<string>)= " << sizeof(__gnu_cxx::__pool_alloc<string>) << endl;         //1 (理論值 0)
		//cout << "sizeof(__gnu_cxx::bitmap_allocator<string>)= " << sizeof(__gnu_cxx::bitmap_allocator<string>) << endl; //1 (理論值 0)
		//cout << "sizeof(__gnu_cxx::__mt_alloc<string>)= " << sizeof(__gnu_cxx::__mt_alloc<string>) << endl;  			//1 (理論值 0)
		//cout << "sizeof(__gnu_cxx::array_allocator<int>)= " << sizeof(__gnu_cxx::array_allocator<int>) << endl;  		//8
		//														//==> 因為它有一個 ptr 指向 array 和一個 size_t 表示消耗到 array 哪兒 
		//cout << "sizeof(__gnu_cxx::debug_allocator<std::allocator<double>>)= " << sizeof(__gnu_cxx::debug_allocator<std::allocator<double>>) << endl; //8 	
	}
}
//---------------------------------------------------
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
namespace jj30
{
	void test_all_components()
	{
		cout << "\ntest_all_components().......... \n";
 
		int ia[7] = { 27, 210, 12, 47, 109, 83, 40 };
		vector<int, allocator<int>> vi(ia, ia + 7);
 
		cout << count_if(vi.begin(), vi.end(),
			not1(bind2nd(less<int>(), 40)));	//5
		cout << endl;
	}
}
//---------------------------------------------------
#include <set>
#include <functional>
#include <iostream>
namespace jj31
{
	//void test_Rb_tree()
	//{
	//	//G2.9 vs. G2.9 : 
	//	  //rb_tree => _Rb_tree, 
	//	  //identity<> => _Identity<>
	//	  //insert_unique() => _M_insert_unique()
	//	  //insert_equal() => _M_insert_equal()
 
	//	cout << "\ntest_Rb_tree().......... \n";
 
	//	_Rb_tree<int, int, _Identity<int>, less<int>> itree;
	//	cout << itree.empty() << endl;  //1
	//	cout << itree.size() << endl;   //0
 
	//	itree._M_insert_unique(3);
	//	itree._M_insert_unique(8);
	//	itree._M_insert_unique(5);
	//	itree._M_insert_unique(9);
	//	itree._M_insert_unique(13);
	//	itree._M_insert_unique(5);  //no effect, since using insert_unique().
	//	cout << itree.empty() << endl;  //0
	//	cout << itree.size() << endl;   //5
	//	cout << itree.count(5) << endl; //1
 
	//	itree._M_insert_equal(5);
	//	itree._M_insert_equal(5);
	//	cout << itree.size() << endl;   //7, since using insert_equal().
	//	cout << itree.count(5) << endl; //3       
	//}
}
//---------------------------------------------------
#include <unordered_set>
#include <functional>
#include <iostream>
#include <string>
namespace jj32
{
	/*
	//下面的 hash<string>, G2.9需要,G4.9不需要,因為 G4.9 basic_string.h 已提供
	template<> struct hash<string>
	{
	  size_t operator()(string s) const {
		  return __stl_hash_string(s.c_str());
	  }
	};
	*/
 
	void test_Hashtable()
	{
		cout << "\ntest_Hashtable().......... \n";
 
		// hashtable 的模板參數個數 6=>10 (增加 hash policy 吧大概)
		// 所以 G2.9的應用修改起來很麻煩。不改了, 以後再說. 	    
	}
}
//---------------------------------------------------
#include <iostream>     // std::cout
#include <iterator>     // std::iterator_traits
#include <typeinfo>     // typeid
namespace jj33
{
	void _display_category(random_access_iterator_tag)
	{
		cout << "random_access_iterator" << endl;
	}
	void _display_category(bidirectional_iterator_tag)
	{
		cout << "bidirectional_iterator" << endl;
	}
	void _display_category(forward_iterator_tag)
	{
		cout << "forward_iterator" << endl;
	}
	void _display_category(output_iterator_tag)
	{
		cout << "output_iterator" << endl;
	}
	void _display_category(input_iterator_tag)
	{
		cout << "input_iterator" << endl;
	}
 
	template<typename I>
	void display_category(I itr)
	{
		typename iterator_traits<I>::iterator_category cagy;
		_display_category(cagy);
 
		cout << "typeid(itr).name()= " << typeid(itr).name() << endl << endl;
		//The output depends on library implementation.
		//The particular representation pointed by the  
		//returned valueis implementation-defined, 
		//and may or may not be different for different types.   
	}
 
	void test_iterator_category()
	{
		cout << "\ntest_iterator_category().......... \n";
 
		display_category(array<int, 10>::iterator());
		display_category(vector<int>::iterator());
		display_category(list<int>::iterator());
		display_category(forward_list<int>::iterator());
		display_category(deque<int>::iterator());
 
		display_category(set<int>::iterator());
		display_category(map<int, int>::iterator());
		display_category(multiset<int>::iterator());
		display_category(multimap<int, int>::iterator());
		display_category(unordered_set<int>::iterator());
		display_category(unordered_map<int, int>::iterator());
		display_category(unordered_multiset<int>::iterator());
		display_category(unordered_multimap<int, int>::iterator());
 
		display_category(istream_iterator<int>());
		display_category(ostream_iterator<int>(cout, ""));
	}
}
//---------------------------------------------------
#include <iostream>     // std::cout
#include <functional>   // std::minus
#include <numeric>      // std::accumulate
namespace jj34
{
	int myfunc(int x, int y) { return x + 2 * y; }
 
	struct myclass {
		int operator()(int x, int y) { return x + 3 * y; }
	} myobj;
 
	void test_accumulate()
	{
		cout << "\ntest_accumulate().......... \n";
		int init = 100;
		int nums[] = { 10,20,30 };
 
		cout << "using default accumulate: ";
		cout << accumulate(nums, nums + 3, init);  //160
		cout << '\n';
 
		cout << "using functional's minus: ";
		cout << accumulate(nums, nums + 3, init, minus<int>()); //40
		cout << '\n';
 
		cout << "using custom function: ";
		cout << accumulate(nums, nums + 3, init, myfunc);	//220
		cout << '\n';
 
		cout << "using custom object: ";
		cout << accumulate(nums, nums + 3, init, myobj);	//280
		cout << '\n';
	}
}
//---------------------------------------------------
#include <iostream>     // std::cout
#include <algorithm>    // std::for_each
#include <vector>       // std::vector
namespace jj35
{
	void myfunc(int i) {
		cout << ' ' << i;
	}
 
	struct myclass {
		void operator() (int i) { cout << ' ' << i; }
	} myobj;
 
	void test_for_each()
	{
		cout << "\ntest_for_each().......... \n";
 
		vector<int> myvec;
		myvec.push_back(10);
		myvec.push_back(20);
		myvec.push_back(30);
 
		for_each(myvec.begin(), myvec.end(), myfunc);
		cout << endl;		//output: 10 20 30
 
		for_each(myvec.begin(), myvec.end(), myobj);
		cout << endl;		//output: 10 20 30
 
		//since C++11, range-based for- statement
		for (auto& elem : myvec)
			elem += 5;
 
		for (auto elem : myvec)
			cout << ' ' << elem; 	//output: 15 25 35
	}
}
//---------------------------------------------------
#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
namespace jj36
{
	bool myfunc(int i, int j) { return (i < j); }
 
	struct myclass {
		bool operator() (int i, int j) { return (i < j); }
	} myobj;
 
	void test_sort()
	{
		cout << "\ntest_sort().......... \n";
 
		int myints[] = { 32,71,12,45,26,80,53,33 };
		vector<int> myvec(myints, myints + 8);          // 32 71 12 45 26 80 53 33
 
		// using default comparison (operator <):
		sort(myvec.begin(), myvec.begin() + 4);         //(12 32 45 71)26 80 53 33
 
		// using function as comp
		sort(myvec.begin() + 4, myvec.end(), myfunc); 	// 12 32 45 71(26 33 53 80)
 
		// using object as comp
		sort(myvec.begin(), myvec.end(), myobj);      //(12 26 32 33 45 53 71 80)
 
		// print out content:
		cout << "\nmyvec contains:";
		for (auto elem : myvec)		//C++11 range-based for statement
			cout << ' ' << elem; 	//output: 12 26 32 33 45 53 71 80
 
	   // using reverse iterators and default comparison (operator <):
		sort(myvec.rbegin(), myvec.rend());
 
		// print out content:
		cout << "\nmyvec contains:";
		for (auto elem : myvec)		//C++11 range-based for statement
			cout << ' ' << elem; 	//output: 80 71 53 45 33 32 26 12    
 
	   // using explicitly default comparison (operator <):
		sort(myvec.begin(), myvec.end(), less<int>());
 
		// print out content:
		cout << "\nmyvec contains:";
		for (auto elem : myvec)		//C++11 range-based for statement
			cout << ' ' << elem; 	//output: 12 26 32 33 45 53 71 80   
 
	   // using another comparision criteria (operator >):
		sort(myvec.begin(), myvec.end(), greater<int>());
 
		// print out content:
		cout << "\nmyvec contains:";
		for (auto elem : myvec)		//C++11 range-based for statement
			cout << ' ' << elem; 	//output: 80 71 53 45 33 32 26 12 	        
	}
}
//---------------------------------------------------
#include <cstdlib> //rand() and RAND_MAX
namespace jjxx
{
	void test_containers()
	{
		int choice;
		long value;
 
		srand(time(NULL));
 
		cout << "\n\ntest_containers()......... \n";
		cout << "select: \n";
		cout << "       (1)array (2)vector (3)list (4)forward_list (5)deque (6)multiset \n";
		cout << "       (7)multimap (8)unordered_multiset (9)unordered_multimap (10)slist \n";
		cout << "       (11)hash_multiset (12)hash_multimap (13)set (14)map (15)unordered_set \n";
		cout << "       (16)unordered_map (17)stack (18)queue \n";
		cout << " (2),(3),(5),(6),(8) will test also moveable elements. \n";
		cin >> choice;
		if (choice != 1) { 	//1 ==> array, use ASIZE
			cout << "how many elements: ";
			cin >> value;
		}
 
		switch (choice)
		{
		case 1: 	jj01::test_array();
			break;
		case 2: 	jj02::test_vector(value);
			//jj02::test_vector_with_move(value);	
			break;
		case 3: 	jj03::test_list(value);
			break;
		case 4: 	jj04::test_forward_list(value);
			break;
		case 5: 	jj05::test_deque(value);
			break;
		case 6: 	jj06::test_multiset(value);
			break;
		case 7: 	jj07::test_multimap(value);
			break;
		case 8: 	jj08::test_unordered_multiset(value);
			break;
		case 9: 	jj09::test_unordered_multimap(value);
			break;
		case 10: 	
			//jj10::test_slist(value);
			break;
		case 11: 	jj11::test_hash_multiset(value);
			break;
		case 12: 	jj12::test_hash_multimap(value);
			break;
		case 13: 	jj13::test_set(value);
			break;
		case 14: 	jj14::test_map(value);
			break;
		case 15: 	jj15::test_unordered_set(value);
			break;
		case 16: 	jj16::test_unordered_map(value);
			break;
		case 17: 	jj17::test_stack(value);
			break;
		case 18: 	jj18::test_queue(value);
			break;
		default:
			break;
		}
	}
}
//---------------------------------------------------
#include <cstdlib> //rand() and RAND_MAX
int main(int argc, char** argv)
{
	//jj00::test_misc();
 
	jjxx::test_containers();
 
	/*jj20::test_list_with_special_allocator();
	jj25::test_components_sizeof();
	jj30::test_all_components();
	jj31::test_Rb_tree();
	jj32::test_Hashtable();
	jj33::test_iterator_category();
	jj34::test_accumulate();
	jj35::test_for_each();
	jj36::test_sort();*/
 
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值