关闭

boost 技术剖析: dynamic_bitset 与 proxy reference

3004人阅读 评论(0) 收藏 举报
先给出 dynamic_bitset 的一个简单示例, 以增加感性认识:
    boost::dynamic_bitset<> a(2);
    a[0] = true;
    a[1] = false;
    if (a[0])
        std::cout << "a[0] holds true/n";

技术要点一: operator[ ] 返回了什么
    返回了引用. 举例来说,
    int a[2];
    a[1] = 3;
    if (a[1] == 4)
       //...
则前者 a[1] = 3 实际上相当于
    int& ra = *(a + 1);
    ra = 3;
后者则相当于
    if (ra == 4)
       //...
所以如果我们要正确重载 operator[ ] , 就也应该返回相应数据的引用, 这一点可以参考std::vector 的实现.

技术要点二: proxy reference
    在 dynamic_bitset 中,显然我们无法返回一个 "bit 引用", 怎么办? 我们做出一个与 "bit 引用"具有相同功能的数据类型. 首先,我们要看看 dynamic_bitset 的内部数据存储, 假设模板参数是unsigned int, 则下面是简化版:
    class dynamic_bitset
    {
       std::vector<unsigned int> m_bits;
       size_type   m_num_bits;
       // ...
    };
    以示例中的 a[1] = false 为例, 我们要引用的是 m_bits 中的第 1 个 unsigned int 的第 2 位, 因此我们的这个冒牌的 reference 看起来应该如下:
    class bit_reference
    {
       unsigned int& m_block;      // 引用第 1 个 unsigned int
       int   m_bit;            // 引用第 1 个 unsigned int 的第 2 位
    public:
       bit_reference(unsigned int& block, int bit)
       : m_block(block), m_bit(bit)
       {}
    };
因为是引用, 我们就应该有能力修改被引用的数据, 所以要紧紧抓住被引用的数据, 这就有了 m_block, 但是我们仅仅引用其中的一位(bit), 所以要记住这一位的位置.
    一般的"reference" 最重要的用处应该有两点: 1.存数据, 2.取数据, 而那个"bit 引用",虽然不存在,但也要求具有这两项功能: 1.存一个bool, 2.取一个 bool. 所以这个 bit_reference 要实现这两点:
    class bit_reference
    {
       // ...
       // 存 bool
       bit_reference& operator=(bool x)   {
          if (x)
             m_block |= (1 << m_bit);
          else
             m_block &= ~(1 << m_bit);
             return *this;
       }

       // 取 bool
       operator bool() const {
          return (m_block & (1 << m_bit) ) != 0;
       }

    有了这个"位引用", 我们就可以在 dynamic_bitset 中用上它了:
    class dynamic_bitset
    {
    // ...
    public:
        bit_reference operator[ ](size_type pos) {
          int nBlock = pos / sizeof(unsigned int);
          int nBit = pos % sizeof(unsigned int);
          return bit_reference(m_bits[nBlock], nBit);
       }
    到现在, 这个冒牌的reference基本上达到了我们的要求, 而且这个 dynamic_bitset 也基本上可以跑起来了,下面我们看看运行的过程, 以最前面的示例为例:
    1. a[0] = true
       调用过程为:
          bit_reference dynamic_bitset::operator[ ](0);
          bit_reference& bit_reference::operator=(bool x);
    2. if (a[1])
       调用过程为:
          bit_reference dynamic_bitset::operator[ ](1);
          bit_reference::operator bool ();

这个 bit_reference 就是我们所说的 proxy reference. 当我们无法实现原有数据类型的引用时, 我们就用另外一种数据类型来模仿这种引用, 而这种数据类型起码要实现两点: 存,取. 从广义上来说, STL 里面的 iterator 大多都是 proxy reference (除vector::iterator), 只是它们实现的功能在数据结构中都是显而易见的, 大家司空见惯了.

proxy reference 还有另外一个用处, 就是写时复制, 我们可以看到: 通过 proxy reference 我们只能从一个地方修改被引用的数据(以bit_reference 为例): bit_reference& operator=(bool x). 在这个函数里,我们就可以很容易地实现写时复制(copy on write). 在 <<The C++ Programming Language>>里有一个 string 类的写时复制实现, 使用的就是这种技术, 我们可以参考.
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:10079次
    • 积分:162
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档