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); //模板拷贝构造
}
Pair的比较:
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);
}
}
make_pair 函数:
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
//效果同上
函数可以利用auto_ptr来传递所有权:
void sink(auto_ptr<ClassA>); //sink get the ownership
//函数返回值拥有所有权
auto_ptr<ClassA> f()
{
auto_ptr<ClassA> ptr(new ClassA);
return ptr; //将所有权移交给函数调用者
}
当你不打算转移auto_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的成员变量:不安全做法,可能导致资源泄露
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;
}
};
为了避免上述资源泄露,使用auto_ptr改进:
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;
}
辅助的函数:Compare 也许是一个函数,也可能是一个函数对象
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;
}
}
max min等函数包含在头文件<algorithm>
#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;
}
swap in <algorithm>:
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;
}
定制自己的swap:
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