zoukankan      html  css  js  c++  java
  • 标准非STL容器 : bitset

    1. 概念
    什么是“标准非STL容器”?标准非STL容器是指“可以认为它们是容器,但是他们并不满足STL容器的所有要求”。前文提到的容器适配器stack、queue及priority_queue都是标准非STL容器的一部分。此外,valarray也是标准非STL容器。
    bitset:一种高效位集合操作容器。

    2. API
    bitset提供的api:
    (constructor)    Construct bitset (public member function)
    operator[]    Access bit (public member function)
    set    Set bits (public member function)
    reset    Reset bits (public member function )
    flip    Flip bits (public member function)
    to_ulong    Convert to unsigned long integer (public member function)
    to_string    Convert to string (public member function)
    count    Count bits set (public member function)
    size    Return size (public member function)
    test    Return bit value (public member function )
    any    Test if any bit is set (public member function)
    none    Test if no bit is set (public member function)

    3. 源码剖析
    SGI bitset部分实现源码

    [cpp] view plain copy
    1. template<size_t _Nb>  
    2. class bitset : private _Base_bitset<__BITSET_WORDS(_Nb)>  
    3. {  
    4. private:  
    5.   typedef _Base_bitset<__BITSET_WORDS(_Nb)> _Base;  
    6.   typedef unsigned long _WordT;  
    7.   
    8. private:  
    9.   void _M_do_sanitize() {  
    10.     _Sanitize<_Nb%__BITS_PER_WORD>::_M_do_sanitize(this->_M_hiword());  
    11.   }  
    12. .....  
    13. }  
    [cpp] view plain copy
    1. #define __BITS_PER_WORD (CHAR_BIT*sizeof(unsigned long))  
    2. #define __BITSET_WORDS(__n)   
    3.  ((__n) < 1 ? 1 : ((__n) + __BITS_PER_WORD - 1)/__BITS_PER_WORD)  
    [cpp] view plain copy
    1. template<size_t _Nw>  
    2. struct _Base_bitset {  
    3.   typedef unsigned long _WordT;  
    4.   
    5.   _WordT _M_w[_Nw];                // 0 is the least significant word.  
    6.   
    7.   _Base_bitset( void ) { _M_do_reset(); }  
    8.   _Base_bitset(unsigned long __val) {  
    9.     _M_do_reset();  
    10.     _M_w[0] = __val;  
    11.   }  
    12.   
    13.   static size_t _S_whichword( size_t __pos )  
    14.     { return __pos / __BITS_PER_WORD; }  
    15.   static size_t _S_whichbyte( size_t __pos )  
    16.     { return (__pos % __BITS_PER_WORD) / CHAR_BIT; }  
    17.   static size_t _S_whichbit( size_t __pos )  
    18.     { return __pos % __BITS_PER_WORD; }  
    19.   static _WordT _S_maskbit( size_t __pos )  
    20.     { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); }  
    21.   
    22.   _WordT& _M_getword(size_t __pos)       { return _M_w[_S_whichword(__pos)]; }  
    23.   _WordT  _M_getword(size_t __pos) const { return _M_w[_S_whichword(__pos)]; }  
    24.   
    25.   _WordT& _M_hiword()       { return _M_w[_Nw - 1]; }  
    26.   _WordT  _M_hiword() const { return _M_w[_Nw - 1]; }  
    27.   
    28.   void _M_do_and(const _Base_bitset<_Nw>& __x) {  
    29.     for ( size_t __i = 0; __i < _Nw; __i++ ) {  
    30.       _M_w[__i] &= __x._M_w[__i];  
    31.     }  
    32.   }  
    33.   
    34.   void _M_do_or(const _Base_bitset<_Nw>& __x) {  
    35.     for ( size_t __i = 0; __i < _Nw; __i++ ) {  
    36.       _M_w[__i] |= __x._M_w[__i];  
    37.     }  
    38.   }  
    39.   
    40.   void _M_do_xor(const _Base_bitset<_Nw>& __x) {  
    41.     for ( size_t __i = 0; __i < _Nw; __i++ ) {  
    42.       _M_w[__i] ^= __x._M_w[__i];  
    43.     }  
    44.   }  

    节选上述代码,可以得到:
    1. bitset继承_Base_bitset,具体操作封装在_Base_bitset中
    2. bitset 的size作为模板参数(非类型模板参数的一个要求是,编译器能在编译期就能把参数确定下来),因此,bitset大小在编译期固定,不支持插入和删除元素
    3. 各种位操作,性能高
    4._Base_bitset使unsigned long作为底层存储,不支持指针、引用、迭代器
    5. 使用 _WordT _M_w[_Nw];分配内存,因此在栈中定义bitset需要注意大小(和STL标准容器堆内存分配区别开)
         eg,下面的代码将栈溢出(测试机器栈内存10M) 
    [cpp] view plain copy
    1. void fun()  
    2. {  
    3.         const int n = 800000000;  
    4.   
    5.         bitset<n> a;  
    6.         cout << a.size() << endl;  
    7. }  
    8. int main(int argc, char** argv)  
    9. {  
    10.         fun();  
    11.   
    12.         return 0;  
    13. }  
    大内存分配可以分配在堆中,如下:
    [cpp] view plain copy
    1. const int n = 800000000;  
    2.   
    3. bitset<n> *a = new(std::nothrow) bitset<n>;  
    4.   
    5. if(a)  
    6. {  
    7.         cout << a->size() << endl;  
    8.         delete a;  
    9.         a = NULL;  
    10. }  
    4. vector<bool>及deque<bool>
    bitset高效,但是size必须在编译器确定,不支持插入和删除。因此,一个可能的替代品是vector<bool>和deque<bool>
    两者的区别:
    vector<bool>不是一个STL容器,并且不容纳bool(like bitse底层t机制)
    deque<bool>是一个STL容器,它保存真正的bool值
    分别运行
    [cpp] view plain copy
    1. deque<bool> a;  
    2. a[0] = 0;  
    3. bool* b = &a[0];  
    4. cout << *b << endl;  

    [cpp] view plain copy
    1. vector<bool> a;  
    2. a[0] = 0;  
    3. bool* b = &a[0];  
    4. cout << *b << endl;  
    将会发现:
    使用deque<bool>正确,而是用vector<bool>会报错:“cannot convert `std::_Bit_reference*' to `bool*' in initialization“

    但是,deque简直是在践踏内存。
    使用deque<bool>
    [cpp] view plain copy
    1. int main(int argc, char** argv)  
    2. {  
    3.         deque<bool> a(10000000000);  
    4.         sleep(100);  
    5.         return 0;  
    6. }  
    内存使用:
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                               
    23612 work      25   0 9990m 9.8g  720 S  0.0 65.0   0:39.35 test

    使用vector<bool>
    [cpp] view plain copy
    1. int main(int argc, char** argv)  
    2. {  
    3.         vector<bool> a(10000000000);  
    4.         sleep(100);  
    5.         return 0;  
    6. }  
    内存使用:
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                               
    23909 work      25   0 1198m 1.2g  716 S  0.0  7.8   0:01.31 test

    使用bitset
    [cpp] view plain copy
    1. int main(int argc, char** argv)  
    2. {  
    3.         const unsigned long int n = 10000000000;  
    4.         bitset<n> *a = new(std::nothrow) bitset<n>;  
    5.         sleep(100);  
    6.   
    7.         return 0;  
    8. }  

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                               
    24439 work      25   0 1198m 1.2g  712 S 30.7  7.8   0:00.92 test  

    10亿个bool,vector<bool>和bitset使用内存1198M,deque<bool>则是9990M


    5. 总结
    在需要对位集合进行操作的时候,如何操作集合大小比较固定,优先选择高效的bitset;
    如果需要动态增删元素,或者编译期间无法确定集合大小,则可以考虑vector<bool>,deque<bool>内存开销太大,基本上不考虑。

    参考:
    http://www.sgi.com/tech/stl/download.html
    http://www.cplusplus.com/reference/stl/vector/
    http://www.cplusplus.com/reference/stl/bitset/

    扩展阅读:

    Vector specialization: vector<bool>

    The vector class template has a special template specialization for the bool type.

    This specialization is provided to optimize for space allocation: In this template specialization, each element occupies only one bit (which is eight times less than the smallest type in C++:char).

    The references to elements of a bool vector returned by the vector members are not references tobool objects, but a special member type which is a reference to a single bit, defined inside thevector<bool> class specialization as:
    [cpp] view plain copy
    1. class vector<bool>::reference {  
    2.   friend class vector;  
    3.   reference();                                 // no public constructor  
    4. public:  
    5.   ~reference();  
    6.   operator bool () const;                      // convert to bool  
    7.   reference& operator= ( const bool x );       // assign from bool  
    8.   reference& operator= ( const reference& x );  // assign from bit  
    9.   void flip();                                 // flip bit value.  
    10. }  
  • 相关阅读:
    How do you Design a Circular FIFO Buffer (Queue) in C?

    搞懂分布式技术5:Zookeeper的配置与集群管理实战
    Spring boot 启动提示数据源错误
    IntelliJ IDEA 如何配置数据源
    Windows 10 中你可能用得最多的快捷键
    JUnit 5 测试问题 throws java.lang.Exception’ must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS)
    Intellij IDEA 如何自动生成 serialVersionUID
    Docsify 初始化文件夹
    Docsify 安装
  • 原文地址:https://www.cnblogs.com/freeopen/p/5483005.html
Copyright © 2011-2022 走看看