我记得《Effective C++》中有这么一条:
条款02 对于单纯常量,最好以const对象或enum替换#define;对于形似函数的宏,最好改用inline函数替换#define
但是Qt中却将define玩的出神入化,宏定义和泛型编程的结合更是令我大开眼见。
本节以Q_GLOBAL_STATIC为例来赏析下Qt中的宏艺术。
Q_GLOBAL_STATIC(TYPE,NAME)宏用来声明定义一个全局的静态变量,一般我们定义全局静态变量如下:
static MyType varname;
也很简单,那Qt中为何要大费周章去定义一个Q_GLOBAL_STATIC宏了,自然是有妙用的。
以上定义语句有如下缺点:
Q_GLOBAL_STATIC宏定义的变量则消除了这些问题,仅在第一次调用时才构造和初始化,节省了应用程序初始化加载的时间,确保了是线程安全的。
让我们分析下源码,看看Q_GLOBAL_STATIC是如何实现并解决这些问题的。
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
namespace { namespace Q_QGS_ ## NAME { \
typedef TYPE Type; \
QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \
Q_GLOBAL_STATIC_INTERNAL(ARGS) \
} } \
static QGlobalStatic NAME;
#define Q_GLOBAL_STATIC(TYPE, NAME) \
Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
Q_GLOBAL_STATIC只是将Q_GLOBAL_STATIC_WITH_ARGS中的ARGS替换成了()
Q_GLOBAL_STATIC_WITH_ARGS中利用了全局变量名NAME是唯一的这一特性,构造了一个独有的命名空间,在Q_QGS_ ## NAME命名空间中定义了一个guard 用来监视状态,下面是几种监视状态的定义:
enum GuardValues {
Destroyed = -2,
Initialized = -1,
Uninitialized = 0,
Initializing = 1
};
使用Q_GLOBAL_STATIC_INTERNAL宏定义了一个innerFunction函数
#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
inline Type *innerFunction() \
{ \
struct HolderBase { \
~HolderBase() Q_DECL_NOTHROW \
{ if (guard.load() == QtGlobalStatic::Initialized) \
guard.store(QtGlobalStatic::Destroyed); } \
}; \
static struct Holder : public HolderBase { \
Type value; \
Holder() \
Q_DECL_NOEXCEPT_EXPR(noexcept(Type ARGS)) \
: value ARGS \
{ guard.store(QtGlobalStatic::Initialized); } \
} holder; \
return &holder.value; \
}
这个函数中定义了一个static Holder变量,即局部static变量,Holder中包裹了我们要定义的类型变量
Type value;
返回值就是这个变量的指针
return &holder.value;
局部static变量在函数第一次调用时初始化,并调用了Type的构造函数
: value ARGS
ARGS被用来传入Type构造函数所需的参数,Q_GLOBAL_STATIC的ARGS是空括号(),表示调用Type的无参构造函数,如果我们使用Q_GLOBAL_STATIC_WITH_ARGS给它参数,就是调用对应的带参构造函数了。
Holder构造函数中将guard状态置为QtGlobalStatic::Initialized,析构时置为QtGlobalStatic::Destroyed
最后一句
static QGlobalStatic NAME;
就是定义了一个static QGlobalStatic变量NAME
看看QGlobalStatic的定义:
template
struct QGlobalStatic
{
typedef T Type;
bool isDestroyed() const { return guard.load() <= QtGlobalStatic::Destroyed; }
bool exists() const { return guard.load() == QtGlobalStatic::Initialized; }
operator Type *() { if (isDestroyed()) return 0; return innerFunction(); }
Type *operator()() { if (isDestroyed()) return 0; return innerFunction(); }
Type *operator->()
{
Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
return innerFunction();
}
Type &operator*()
{
Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
return *innerFunction();
}
};
模板参数传入真正的类型TYPE,刚刚在G_QGS_##NAME命名空间中定义的innerFunction函数,和guard状态变量,重载了括号()、指针->、取值操作符*,使得NAME变量(其实是对象)表现得像一个指针。