c++ - unsigned char 变量不递增

标签 c++

我遇到了一种奇怪的行为。在我的代码中,一个变量被递减,但没有递增,因此我的算法不起作用。变量名为blocksAvailable,定义在Chunk类中,用Chunk::init方法发起,用Chunk::递减allocate 方法,并且必须使用 Chunk::deallocate 方法递增。因此,只有两个地方提到了这个变量 - allocatedeallocate 方法。在一个地方它会递减(并且有效),而在其他地方它会递增并且不起作用。这是完全最小化且可重现的代码:

#include <cstddef>
#include <iostream>
#include <vector>

using uchar = unsigned char;

class Chunk 
{
private:    

    friend class FixedAllocator;

    void init(size_t blockSize, uchar blocks);

    void release();

    void* allocate(size_t blockSize);

    void deallocate(void* p, size_t blockSize);

    inline bool hasBlock(void* p, size_t chunkLen) const
    {
        uchar * pc = static_cast<uchar*>(p);
        return (pData <= pc) && (pc <= (pData + chunkLen));
    }

    inline bool releasable(uchar numBlocks) const
    {
          return blocksAvailable == numBlocks;    
    }

    uchar* pData;

    uchar firstAvailableBlock, blocksAvailable;    
};

void Chunk::init(size_t blockSize, uchar blocks)
{
     // for n of Ts it will allocate n * sizeof(T) memory
    pData = new uchar[blockSize * blocks];
    firstAvailableBlock = 0;
    blocksAvailable = blocks;
    uchar i = 0;
    uchar* p = pData;
    // used by allocate method to move forward firstAvailableBlock 
    for (; i != blocks; p += blockSize) 
    {
          *p = ++i;
    }
}

void Chunk::release()
{
    ::operator delete(pData);
}

void* Chunk::allocate(size_t blockSize)
{
     if (!blocksAvailable) return 0;
     // move firstAvailableBlock one block ahead
    uchar* pResult = pData + firstAvailableBlock * blockSize;
    firstAvailableBlock = *pResult;
    --blocksAvailable;
    std::cout << "blocksAvailable after allocate " << blocksAvailable << std::endl;
    return pResult;
}

void Chunk::deallocate(void* p, size_t blockSize)
{
    uchar* toRelease = static_cast<uchar*>(p);
    // find last but one available block
    firstAvailableBlock = static_cast<uchar>((toRelease - pData) / blockSize);
    ++blocksAvailable;
    std::cout << "blocksAvailable after deallocate " << blocksAvailable << std::endl;
}

class FixedAllocator 
{
private:
    size_t blockSize;
    uchar blocks;
    using Chunks = std::vector<Chunk>;
    Chunks chunks;
    Chunk* allocChunk;
public:
    FixedAllocator();
    ~FixedAllocator();
    void init(size_t blockSize, size_t pageSize);
    const int blockOwner(void* p) const;
    void * allocate();
    void deallocate(void* p);
};

FixedAllocator::FixedAllocator()
    :blockSize(0),
    blocks(0),
    chunks(0),
    allocChunk(nullptr)
{
}

FixedAllocator::~FixedAllocator()
{
    Chunks::iterator it;
    for (it = chunks.begin(); it != chunks.end(); ++it)
    {
        it->release();    
    }
}

void FixedAllocator::init(size_t blockSize_, size_t pageSize)
{
     blockSize = blockSize_;
    size_t numBlocks = pageSize / blockSize;
    blocks = static_cast<uchar>(numBlocks);
}

const int FixedAllocator::blockOwner(void* p) const
{
    size_t chunkLen = blocks * blockSize;
    std::vector<int>::size_type i = 0, sz = chunks.size();
    for (; i < sz; i++)
    {
          if (chunks[i].hasBlock(p, chunkLen))
        {
               return i;        
        }    
    }
    return -1;
}

void* FixedAllocator::allocate()
{
     if (!allocChunk || allocChunk->blocksAvailable == 0)
    {
        Chunks::iterator i = chunks.begin();    
        for (;;++i)
        {
            if (i == chunks.end())
            {
                 // allocate memory for one more chunk
                chunks.reserve(chunks.size() + 1);
                Chunk newChunk;  
                newChunk.init(blockSize, blocks);
                // add new chunk to memory pool
                chunks.push_back(newChunk);                
                // points to new just initiated chunk
                allocChunk = &chunks.back();
                break;
            }
            if (i->blocksAvailable > 0)
            {
                 // points to chunk with available blocks
                allocChunk = &*i;
                break;            
            }                   
        }
    }
    return allocChunk->allocate(blockSize);
}

void FixedAllocator::deallocate(void* p)
{
    // TODO. Optimize. Now very bruteforce and non-efficient
    const int chunkPos = blockOwner(p); 
    if (chunkPos != -1) 
    {
           Chunk chunk = chunks[chunkPos];
           chunk.deallocate(p, blockSize);         
         // if chunk is releasable, release memory 
         if (chunk.releasable(blocks))
         {
             chunk.release();
             chunks.erase(chunks.begin() + chunkPos);
             // allocChunk may point to deleted chunk
             // so, reset it                      
             allocChunk = &chunks.back();
         } else {
             // there are free blocks in chunk
             // so, reset allocChunk for faster future allocation
             allocChunk = &chunk;    
         }         
    }    
}

int main() {
     FixedAllocator* alloc = new FixedAllocator();
     alloc->init(4, 12);
     void* p = alloc->allocate();
     void* q = alloc->allocate();
     void* r = alloc->allocate();
     alloc->deallocate(p);
     alloc->deallocate(q);
     alloc->deallocate(r);   
     return 0;
}

如您所见,我的代码中有两个调试语句。一种在递增后打印 blocksAvailable 值,另一种在递减后打印其值。

但这是我在编译和运行代码时在屏幕上看到的:

enter image description here

如您所见,blocksAvailable 以值 3 启动,然后递减三次(三次调用 allocate 方法),但在每次递减(调用 deallocate)后,它的值保持不变 - 1。它真的让我发疯,看起来像我代码中的幽灵。您可以轻松地重现、编译和运行它,就像:

$ g++ main.cpp
$ ./a.out

我希望有人能帮我找到这个幽灵是从哪里出现的。

最佳答案

这是代码中唯一调用 Chunk::deallocate 的地方:

       Chunk chunk = chunks[chunkPos];
       chunk.deallocate(p, blockSize);

第一行复制了你的Chunk;第二行对其调用 deallocate,这会增加 chunk.blocksAvailable。但是 chunk 只是数据的一个拷贝。修改它没有持久的效果。

特别是,chunks[chunkPos] 不受影响并且仍然包含 blocksAvailable = 0

关于c++ - unsigned char 变量不递增,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48095828/

相关文章:

C++ 私有(private)函数 - 不在此范围内错误

c++ - 这是溢出吗?

c++ - 我如何链接到 Ubuntu 上的 Qwt 库?

C++ 问题 - getline 跳过第一个输入

c++ - Visual Studio C++ 中的 DDALine

c++ - 如何使用 bind 基于::second pair 成员排序的 std::pair 创建集合

C++ 为什么我的指针选择排序中存在段错误?

c++ - 为什么 Boost unordered_map 在第一次插入时花费太多时间?

C++ 在 vector 中访问 vector 中的字符串

c++ - C/C++,NTFS。多个重解析点