Chinaunix首页 | 论坛 | 博客
  • 博客访问: 135665
  • 博文数量: 13
  • 博客积分: 431
  • 博客等级: 下士
  • 技术积分: 166
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-18 14:59
文章分类

全部博文(13)

文章存档

2012年(9)

2011年(4)

分类: C/C++

2012-01-08 18:29:03

STL中提供了bitset,这个数据类型可以认为是vector的简化版本(大小在编译器确定,不能扩展),在这个容器类相对简单,它的成员函数count用来计算bitset中存在的bit位的数量:
(注:_M_do_count是bitset的base class _Base_bitset的实现,在bitset的count中直接调用了该函数)

最开始我以为该函数会针对每个字节使用移位来累计bit位的个数,直到我看到下面红色的代码的部分:
  1. size_t _M_do_count() const {
  2.         size_t __result = 0;
  3.         const unsigned char* __byte_ptr = (const unsigned char*)_M_w;
  4.         const unsigned char* __end_ptr = (const unsigned char*)(_M_w+_Nw);
  5.         while ( __byte_ptr < __end_ptr ) {
  6.           __result += _Bit_count<true>::_S_bit_count[*__byte_ptr];
  7.           __byte_ptr++;
  8.         }
  9.         return __result;
  10.       }
该实现使用了这个_Bit_count模板类的静态成员_S_bit_count来获取每一个字节的bit数,避免了移位计算带来的开销。下面是该模板类和它静态成员的声明:
  1. // structure to aid in counting bits
  2. template<bool __dummy>
  3. struct _Bit_count {
  4.   static unsigned char _S_bit_count[256];
  5. };

  1. template<bool __dummy>
  2. unsigned char _Bit_count<__dummy>::_S_bit_count[] = {
  3.   0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
  4. ...
  5. };
(注:为了节省篇幅,只列出了其中256个元素中的5个)
但是,为什么使用这样繁琐的方式来使用呢?

1)如果直接定义为全局变量:
  1. unsigned char _S_bit_count[] = {
  2.   0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
  3. };
使用这种方式会导致多个包含bitset.h的文件在链接时出现多重定义的错误。

2)如果定义为静态全局变量:
  1. static unsigned char _S_bit_count[] = {
  2.     0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
  3. };
这种方式会导致每个包含bitset.h的文件都存在一个副本,浪费空间。

3)如果定义为类的静态成员:
  1. struct _Bit_count {
  2.   static unsigned char _S_bit_count[256];
  3. };

  4. unsigned char _Bit_count::_S_bit_count[] = {
  5.   0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */
  6. };
这种方式有和全局变量一样的问题:多个包含bitset.h的文件链接时会导致多重定义。

以上。

若不使用bitset的count成员函数,编译器不会生成_Bit_count的定义,也就不会定义_Bit_count::_S_bit_count,优化了空间的使用。

根据进一步的测试发现:即使产生了模板类的一个实例,若代码中没有访问该类的静态成员,静态成员并不会初始化。这不知是语言的标准行为还是编译器优化的结果。

测试代码:
  1. #include <iostream>

  2. using namespace std;

  3. class object {
  4. public:
  5.     object(void) { cout << "object() at " << this << endl; }
  6. };

  7. template <int dumb>
  8. class dummy {
  9. public:
  10.     dummy(void) { cout << "dummy() at " << this << endl; }

  11.     static object obj;
  12. };

  13. template <int n>
  14. object dummy<n>::obj;

  15. int main(int argc, char **argv)
  16. {
  17.     cout << "begin" << endl;

  18.     dummy<0> a;

  19.     // 即使已经产生了dummy<0>的定义,若没有访问dummy<0>::obj的代码,dummy<0>::obj依然不会初始化。
  20. // object *p = &a.obj;

  21.     return 0;
  22. }
阅读(3858) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~