STL中提供了bitset,这个数据类型可以认为是vector
的简化版本(大小在编译器确定,不能扩展),在这个容器类相对简单,它的成员函数count用来计算bitset中存在的bit位的数量:
(注:_M_do_count是bitset的base class _Base_bitset的实现,在bitset的count中直接调用了该函数)
最开始我以为该函数会针对每个字节使用移位来累计bit位的个数,直到我看到下面红色的代码的部分:
-
size_t _M_do_count() const {
-
size_t __result = 0;
-
const unsigned char* __byte_ptr = (const unsigned char*)_M_w;
-
const unsigned char* __end_ptr = (const unsigned char*)(_M_w+_Nw);
-
while ( __byte_ptr < __end_ptr ) {
-
__result += _Bit_count<true>::_S_bit_count[*__byte_ptr];
-
__byte_ptr++;
-
}
-
return __result;
-
}
该实现使用了这个_Bit_count模板类的静态成员_S_bit_count来获取每一个字节的bit数,避免了移位计算带来的开销。下面是该模板类和它静态成员的声明:
-
// structure to aid in counting bits
-
template<bool __dummy>
-
struct _Bit_count {
-
static unsigned char _S_bit_count[256];
-
};
-
template<bool __dummy>
-
unsigned char _Bit_count<__dummy>::_S_bit_count[] = {
-
0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
-
...
-
};
(注:为了节省篇幅,只列出了其中256个元素中的5个)
但是,为什么使用这样繁琐的方式来使用呢?
1)如果直接定义为全局变量:
-
unsigned char _S_bit_count[] = {
-
0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
-
};
使用这种方式会导致多个包含bitset.h的文件在链接时出现多重定义的错误。
2)如果定义为静态全局变量:
-
static unsigned char _S_bit_count[] = {
-
0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
-
};
这种方式会导致每个包含bitset.h的文件都存在一个副本,浪费空间。
3)如果定义为类的静态成员:
-
struct _Bit_count {
-
static unsigned char _S_bit_count[256];
-
};
-
-
unsigned char _Bit_count::_S_bit_count[] = {
-
0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
-
};
这种方式有和全局变量一样的问题:多个包含bitset.h的文件链接时会导致多重定义。
以上。
若不使用bitset的count成员函数,编译器不会生成_Bit_count的定义,也就不会定义_Bit_count::_S_bit_count,优化了空间的使用。
根据进一步的测试发现:即使产生了模板类的一个实例,若代码中没有访问该类的静态成员,静态成员并不会初始化。这不知是语言的标准行为还是编译器优化的结果。
测试代码:
-
#include <iostream>
-
-
using namespace std;
-
-
class object {
-
public:
-
object(void) { cout << "object() at " << this << endl; }
-
};
-
-
template <int dumb>
-
class dummy {
-
public:
-
dummy(void) { cout << "dummy() at " << this << endl; }
-
-
static object obj;
-
};
-
-
template <int n>
-
object dummy<n>::obj;
-
-
int main(int argc, char **argv)
-
{
-
cout << "begin" << endl;
-
-
dummy<0> a;
-
-
// 即使已经产生了dummy<0>的定义,若没有访问dummy<0>::obj的代码,dummy<0>::obj依然不会初始化。
-
// object *p = &a.obj;
-
-
return 0;
-
}
阅读(3835) | 评论(0) | 转发(0) |