Pairs: #include <utility>
std::pair是一个未封装类:struct class
两个成员:first second
一个函数:make_pair(const T1&, const T2&)
默认的构造函数对于基础类型会初始化:
std::pair<int, float> p; //p.first =0 and p.second = 0
两个拷贝构造函数:默认的和模板
void f(std::pair<int, const char*>); voif g(std::pair<const int, std::string>); voif foo() { std::pair<int, const char*> p(42, "hello"); f(p); //内置的拷贝构造函数 g(p); //模板拷贝构造 }
namespace std { template<class T1, class T2> bool operator==(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y) { return x.first == y.first && x.second == y.second; } } namespace std { template<class T1, class T2> bool operator<(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y) { return x.first < y.first || (!(x.fist < y.fist) && x.second < y.second); } }
namespace std { template<class T1, class T2> pair<T1,T2> make_pair(const T1& x, const T2& y) { return pair<T1,T2>(x,y); } }
void f(std::pair<int, const char*>); voif g(std::pair<const int, std::string>); voif foo() { f(std::make_pair(43, "hel")); //内置的拷贝构造函数 g(std::make_pair(43, "hel")); //模板拷贝构造 }
在map和multimap容器里大量使用 pair表示键值对:
Class auto_ptr:智能指针以避免资源泄露
传统手动销毁资源new和delete,很容易忘记delete导致内存泄露:
void f() { ClassA* aPtr = new ClassA; //创建一个堆对象 ... delete aPtr; //销毁这个对象 }改进版:
void f() { ClassA* aPtr = new ClassA; //创建一个堆对象 try { ... } catch (...) { delete aPtr; throw; } ... delete aPtr; //销毁这个对象 }更好的选择:只能指针auto_ptr
#include <memory> void f() { std::auto_ptr<ClassA> pClassA(new ClassA); //... std::auto_ptr<ClassA> pClassAError = new ClassA; //error }
auto_ptr类似于指针变量:提供了*解引用和->箭头取成员函数或对象操作。
但是,auto_ptr提供严格的所有者权限审察,一个auto_ptr对象管理它指向的资源,而这个资源不应该被其他对象拥有,不幸的是C++语言没有在语言级别上限制,需要程序员自己控制。导致这个情况的是拷贝构造函数和赋值操作符的处理。
std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2(ptr1); //now ptr2 has the ownership, when ptr2 delete and the object destroyed std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2; ptr2 = ptr1; //copy assignment //效果同上
void sink(auto_ptr<ClassA>); //sink get the ownership //函数返回值拥有所有权 auto_ptr<ClassA> f() { auto_ptr<ClassA> ptr(new ClassA); return ptr; //将所有权移交给函数调用者 }
template <class T> void bad_print(auto_ptr<T> p) { if(p.get() == NULL) { cout << "NULL" << endl; } else { cout << *p << endl; } } 客户端这样使用: auto_ptr<int> p(new int); *p = 10; bad_print(p); //delete the memory that p refer *p = 20; //runtime error
避免传递auto_ptr的引用到函数:
const 意味着你不能改变auto_ptr的所有权而非指针所指向的对象的值:
auto_ptr<int> void f() { const auto_ptr<int> p(new int); //no ownership transfer auto_ptr<int> q(new int); //ownership transfer possible *p = 42; //ok bad_print(p); //complie-time error *p = *q; //ok p = q; //error return p; //error }
class B { private: A *pA1; A *pA2; public: //当第二个new抛异常时候可能会导致资源泄露 B(A a1, A a2) : pA1(new A(a1)), pA2(new A(a2)) { } //同上 B(const B& x) : pA1(new A(*x.pA1)), pA2(new A(*x.pA2)) //拷贝运算符 const B& operator=(const B& x) { *pA1 = *x.pA1; *pA2 = *x.pA2; return *this; } //析构函数 ~B() { delete pA1; delete pA2; } };
class B { private: const auto_ptr<A> pA1; const auto_ptr<A> pA2; public: //当第二个new抛异常时候可能会导致资源泄露 B(A a1, A a2) : pA1(new A(a1)), pA2(new A(a2)) { } //同上 B(const B& x) : pA1(new A(*x.pA1)), pA2(new A(*x.pA2)) //拷贝运算符 const B& operator=(const B& x) { *pA1 = *x.pA1; *pA2 = *x.pA2; return *this; } //这里就不需要析构函数 };
注意:auto_ptr使用指南
不能共享所有权
不能应用于array,auto_ptr call delete not delete[]
不是通用的智能指针
针对容器,无用武之地:因为coping不是常规的复制,而是transfer所有权
一个小例子:auto_ptr转移所有权,注意const auto_ptr<T>& p const保证了函数不会转移所有权
#include <iostream> #include <memory> //auto_ptr头文件 using namespace std; //为auto_ptr定义输出操作符<< template <class T> ostream& operator<<(ostream& os, const auto_ptr<T>& p) { if(p.get() == NULL) { os << "NULL"; } else { os << *p; } return os; } int main() { auto_ptr<int> p(new int(42)); auto_ptr<int> q; cout << "after initialization : " << endl; cout << "p = " << p << endl; //p = 42 cout << "q = " << q << endl; //q = NULL q = p; cout << "after assigning auto_ptr : " << endl; cout << "p = " << p << endl; //p = NULL cout << "q = " << q << endl; //q = 42 *q = *q + 58; p = q; cout << "after change *q and reassign : " << endl; cout << "p = " << p << endl; //p = 100 cout << "q = " << q << endl; //q = NULL return 0; }
auto_ptr<int> p = new int(9); //error, 因为auto_ptr对基础类型的构造函数是explicit不能进行隐式转换
下面的小例子展示了auto_ptr的const用法:
#include <iostream> #include <memory> //auto_ptr头文件 using namespace std; //为auto_ptr定义输出操作符<< template <class T> ostream& operator<<(ostream& os, const auto_ptr<T>& p) { if(p.get() == NULL) { os << "NULL"; } else { os << *p; } return os; } int main() { const auto_ptr<int> p(new int(42)); const auto_ptr<int> q(new int(0)); const auto_ptr<int> r; cout << "after initialization : " << endl; cout << "p = " << p << endl; //p = 42 cout << "q = " << q << endl; //q = 0 cout << "r = " << r << endl; // r = NULL *q = *p; //*r = *p; //error at compile *p = -77; cout << "after assigning values auto_ptr point to: " << endl; cout << "p = " << p << endl; //p = -77 cout << "q = " << q << endl; //q = 42 cout << "r = " << r << endl; // r = NULL //q = p; //compile error //r = p; //compile error return 0; }
Numeric limits:
C++ 标准库提供了numeric_limits模板:提供更安全的类型
平台无关的代码:尽量使用类型保证的最小精度
类型 | 最小大小 |
char | 1 byte = 8 bits |
short int | 2 bytes |
int | 2 bytes |
long int | 4 bytes |
float | 4 bytes |
double | 8 bytes |
long double | 8 bytes |
class numeric_limits<>: #include <limits>
#include <iostream> #include <limits> #include <string> using namespace std; int main() { //对于bool类型,使用文本方式输出 cout << boolalpha; cout << "max(short) : " << numeric_limits<short>::max() << endl; //max(short) : 32767 cout << "max(int) : " << numeric_limits<int>::max() << endl; //max(int) : 2147483647 cout << "max(long) : " << numeric_limits<long>::max() << endl; //max(long) : 9223372036854775807 cout << "max(float) : " << numeric_limits<float>::max() << endl; //max(float) : 3.40282e+38 cout << "max(double) : " << numeric_limits<double>::max() << endl; //max(double) : 1.79769e+308 cout << "max(long double) : " << numeric_limits<long double>::max() << endl; //max(long double) : 1.18973e+4932 cout << "is_signed(char) : " << numeric_limits<char>::is_signed << endl; //is_signed(char) : true cout << "is_specialized(string) : " << numeric_limits<string>::is_specialized << endl; //is_specialized(string) : false return 0; }
namespace std { template <class T> inline const T& min(const T& a, const T& b) { return a < b ? a : b; } template <class T> inline const T& max(const T& a, const T& b) { return a < b ? b : a; } } //如果a == b 总是返回第二个 //于是两个参数的比较出来了 namespace std { template <class T, class Compare> inline const T& min(const T& a, const T& b, Compare comp) { return comp(b,a) ? a : b; } template <class T> inline const T& max(const T& a, const T& b) { return comp(a,b) ? b : a; } }
#include <iostream> #include <algorithm> //算法 using namespace std; bool int_ptr_less(int *a, int *b) { return *a < *b; } int main() { int x = 17; int y = 42; int *px = &x; int *py = &y; int *pMax = max(px, py, int_ptr_less); cout << *pMax << endl; //42 int i = 0; long l = 1; //long m = max(i, l); //error argument doesn't match long m = max<long>(i, l); //ok return 0; }
namespace std { template <class T> inline void swap(T& a, T& b) { T tmp(a); a = b; b = tmp; } } #include <iostream> #include <algorithm> //算法 using namespace std; int main() { int x = 17; int y = 42; int *pX = &x; int *pY = &y; swap(x, y); cout << "x = " << x << endl; //42 cout << "y = " << y << endl; //17 cout << "*pX = " << *pX << endl; //42 cout << "*pY = " << *pY << endl << endl; //17 swap(pX, pY); cout << "x = " << x << endl; //42 cout << "y = " << y << endl; //17 cout << "*pX = " << *pX << endl; //17 cout << "*pY = " << *pY << endl; //42 return 0; }
class MyContainer { private: int *elems; //dynamic array of elements int numElems; public: void swap(MyContainer& x) { std::swap(elems, x.elems); std::swap(numElems, x.numElems); } }; inline void swap(MyContainer& c1, MyContainer& c2) { c1.swap(c2); //调用自己的swap()实现 }
定义在<cstddef>:
NULL:指针值没有定义或者没有值
size_t :number of elements unsigned
ptrdiff_t :signed type for difference of point
offsetof() : offset of a member in structure
定义在<cstdlib>:
exit(int status) 退出程序
EXIT_SUCCESS
EXIT_FAILURE
abort()
atexit() //call function on exit