该__COUNTER__
符号由VC++和GCC提供,并在每次使用时提供增加的非负积分值.
我有兴趣了解是否有人曾经使用它,以及它是否值得标准化?
__COUNTER__
在您需要唯一名称的任何地方都很有用.我已广泛用于RAII风格的锁和堆栈.考虑:
struct TLock { void Lock(); void Unlock(); } g_Lock1, g_Lock2; struct TLockUse { TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); } ~TLockUse(){ m_Lock.Unlock(); } TLock &m_Lock; }; void DoSomething() { TLockUse lock_use1( g_Lock1 ); TLockUse lock_use2( g_Lock2 ); // ... }
将锁定用途命名为繁琐,如果它们并非全部在块顶部声明,则甚至可能成为错误源.你怎么知道你是否在lock_use4
或lock_use11
?这也是名称空间不必要的污染 - 我永远不需要通过名称来引用锁定使用对象.所以我使用__COUNTER__
:
#define CONCAT_IMPL( x, y ) x##y #define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y ) #define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock ) void DoSomething2() { USE_LOCK( g_Lock1 ); USE_LOCK( g_Lock2 ); // ... }
但是不要挂断我调用对象锁的事实 - 任何需要在匹配对中调用的函数都适合这种模式.您甚至可能在给定块中的同一"锁定"上有多个用途.
我在编译时断言宏中使用它让宏为typedef创建一个唯一的名称.看到
在C语言中在构建时ASSERT表达式的方法
如果你想要血淋淋的细节.
除了DEBUG宏之外,我从未使用它.能够说得很方便
#define WAYPOINT \ do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);
它在xCover代码覆盖库中使用,用于标记执行所经过的行,以查找未覆盖的行.
我有兴趣了解是否有人曾经使用它,
是的,但正如您在本问答中的许多示例中所看到的那样__LINE__
,在大多数情况下标准化也是足够的.
__COUNTER__
只有在每次计数必须增加一个的情况下,或者它必须具有几个#include
文件的连续性时才是真正必要的.
以及它是否值得标准化?
__COUNTER__
,不像__LINE__
,是非常危险的,因为它取决于包含哪些头文件和什么顺序.如果两个.cpp
文件(翻译单元)包含使用的头文件__COUNTER__
,但是头文件在不同的实例中获得不同的计数序列,则它们可能使用相同事物的不同定义并违反单定义规则.
违反单定义规则非常难以捕获并可能产生错误和安全风险.少数用例__COUNTER__
并没有真正超过缺点和缺乏可扩展性.
即使您从未提供使用的代码,__COUNTER__
在对枚举序列进行原型设计时也很有用,这样可以省去在具体成员资格之前分配名称的麻烦.