我遇到了一种奇怪的行为。在我的代码中,一个变量减少了,但没有增加,因此我的算法不起作用。变量名称为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值,另一种在递减后打印blocksAvailable值。

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

c&#43;&#43; - 无符号char变量不增加-LMLPHP

如您所见,3用值allocate初始化,然后递减3次(对deallocate方法的三个调用),但是在每次递减(对1的调用)之后,其值保持不变-ojit_code。这确实使我发疯,并且在我的代码中看起来有些鬼。您可以轻松地复制,编译和运行它,就像:
$ 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++ - 无符号char变量不增加,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48095828/

10-16 03:07