目录
RAII(Resource Acquisition Is Initialization)
ScopeGuard
NVI(Non-Virtual Interface)
CRTP(Curiously Recurring Template Pattern)
PIMPL(Private Implementation)
SFINAE(Substitution Failure Is Not An Error)
RAII(Resource Acquisition Is Initialization)
即资源获取就是初始化,是一种管理资源的机制。
如管理new操作符的资源:
class A
{
public:
int *p;
A(int n)
{
p = new int[n];
}
~A()
{
delete p;
}
};
int main()
{
A a(10);
// a.p
return 0;
}
只写了一个简单的示例。
一个经典的案例:lock_guard类,源代码如下
// CLASS TEMPLATE lock_guard templateclass lock_guard { // class with destructor that unlocks a mutex public: using mutex_type = _Mutex; explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock _MyMutex.lock(); } lock_guard(_Mutex& _Mtx, adopt_lock_t) : _MyMutex(_Mtx) { // construct but don't lock } ~lock_guard() noexcept { // unlock _MyMutex.unlock(); } lock_guard(const lock_guard&) = delete; lock_guard& operator=(const lock_guard&) = delete; private: _Mutex& _MyMutex; };
实例化的时候加锁,生命周期结束的时候自动解锁。
ScopeGuard
这个方法是定义一个ScopeGuard模板类,用于管理临时使用的资源。
把临时资源的释放操作写成lambda表达式,申请ScopeGuard实例存放这个表达式,实例生命周期结束时自动
代码:
templateclass ScopeGuard { public: ScopeGuard(Lambda &&lam): lambda (lam) { } ~ScopeGuard() { lambda(); } private: Lambda lambda; }; template ScopeGuard GetScopeGuard(T &&lambda) { return ScopeGuard (move(lambda)); } int main() { int* p = new int[100]; GetScopeGuard([&] {delete[] p; }); return 0; }
NVI(Non-Virtual Interface)
NVI是用非虚函数调用虚函数,把非虚函数作为接口。
class A
{
public:
void show()
{
cout << "An";
print();
}
virtual void print() {};
};
class B :public A
{
public:
void print()
{
cout << "x=" << x;
}
private:
int x;
};
int main()
{
B b;
b.show();
return 0;
}
CRTP(Curiously Recurring Template Pattern)
奇异的递归模板模式,指的是子类继承一个模板类,模板的特化类型是子类本身。
最简代码:
#includeusing namespace std; template class Base { public: void virtualFunc() { static_cast (this)->realFunc(); } }; class Chird :public Base { public: void realFunc() { cout << "real func"; } }; int main() { Chird().virtualFunc(); return 0; }
这个简单的例子就能看出CRTP的写法,也能看出,其实本质上静态多态。
CRTP的好处是,静态多态比继承虚函数的动态多态要快。
应用:
CRTP单例模板
CRTP + 模板方法模式
PIMPL(Private Implementation)
通过一个私有的成员指针,将指针所指向的类的内部实现全部隐藏。
普通代码:
class A
{
public:
int f(int n)
{
return f1(n) + n + f2(n);
}
private:
int f1(int n)
{
return n * n * n;
}
int f2(int n)
{
return n > 0 ? 1 : -1;
}
};
PIMPL代码:
class B;
class A
{
public:
A()
{
opt = new B();
}
int f(int n)
{
return opt->f1(n) + n + opt->f2(n);
}
private:
B* opt;
};
class B
{
public:
int f1(int n)
{
return n * n * n;
}
int f2(int n)
{
return n > 0 ? 1 : -1;
}
};
SFINAE(Substitution Failure Is Not An Error)
SFINAE是指泛型函数在编译的时候,会尝试生成所有实例,如果生成失败也不会报错,直到最后确定重载版本的时候如果没有正确版本才会报错。
templatevoid print(T x) { cout << x; } void print(vector x) { cout << x[0]; } int main() { vector x = { 1,2,3 }; print(x); return 0; }
在这个例子中,泛型函数print首先会生成实例,但是里面会编译失败,继续编译,普通函数print可以满足条件,最终选用它而忽略泛型实例。
应用:通过重载版本判断一个参数类型是不是类
class A
{
//
};
class IsClass
{
public:
template static char f(int C::*);
template static int f(...);
};
int main()
{
bool flag1 = sizeof(IsClass::f(0)) == 1; // true
bool flag2 = sizeof(IsClass::f(0)) == 1; // false
return 0;
}



