[数组包装器破坏堆栈

问题描述 投票:0回答:1

我的项目是一个动态数组包装器,如std :: vector。它是这样工作的:

  • 添加新元素时,如果内存为0,则分配内存(malloc);如果不为0,则以新大小重新分配内存(realloc)。如果内存为0,则大小为元素数*大小类型

  • 当获得已经添加的元素时,我通过将其索引乘以类型的大小并将其添加到分配内存的地址来计算地址

注意:我自己编写和读取内存,没有像memcpy或memset这样的功能。这是我的项目所必需的。我应该有可能这样做,所以如果可以的话,不要提及它(除非我实施错了,在这种情况下,请提及)

[当我尝试使用get(int index)函数读取添加的元素时,我会遇到“变量周围的堆栈已损坏”或“读取访问冲突”错误,具体取决于我如何执行此操作。

我在线上阅读了一下,发现我可能已经用malloc破坏了堆。还阅读了我可以找出错误所在“ valgrind”,但是它似乎仅适用于linux,并且我使用Windows。

这是我的代码(已将其重写,删除了所有错误检查以使其更小)。我收到错误的地方被评论:

template<class T>
class darr
{
public:
    darr(void) {}
    ~darr(void) {
        erase(); dealloc();
    }

    bool alloc(int elemc) {
        this->elemc = elemc;
        this->size = (elemc * sizeof(T));
        this->end = (this->start + this->size);

        if (this->start)
        {
            this->start = (T*)(realloc(this->start, this->size));

            if (this->start)
            {
                this->end = (this->start + this->size);
                return true;
            }
        }
        else
        {
            this->start = (T*)(malloc(this->size));

            if (this->start)
            {
                this->end = (this->start + this->size);
                return true;
            }
        }

        return false;
    }

    bool erase(void)
    {
        for (int i = 0; i <= this->size; ++i)
        {
            *(unsigned long*)(this->start + i) = 0;
        }

        return true;
    }

    bool dealloc(void)
    {
        free(this->start);

        return true;
    }

    bool add(T obj)
    {
        void* end_temp = 0;

        if (this->end) { end_temp = this->end; }

        if (true == this->alloc(++this->elemc))
        {
            end_temp = this->end;

            for (int i = 0; i <= sizeof(obj); ++i)
            {
                *(unsigned long*)((unsigned long)(end_temp)+i) = *(unsigned long*)((unsigned long)(&obj) + i);
            }
        }

        return true;
    }

    T get(int i)
    {
        unsigned long siz = sizeof(T);
        void* i_addr = this->start + (i * siz);

        //T tempobj = 0;
        T* tempobj = (T*)(malloc(sizeof(T)));
        // without malloc - stack around var corrupted (happnens at last index in for loop, no matter what index it is)
        // with malloc - read access violation
        for (int i = 0; i <= siz; ++i)
        {
            *(unsigned long*)((unsigned long)(&tempobj)+i) = *(unsigned long*)((unsigned long)(i_addr)+i);
        }

        return *tempobj;
    }
private:
    T * start;
    void* end;
    int elemc, size;
};
c++ memory-management heap heap-corruption
1个回答
0
投票

让我们拆开代码并慢慢修复。从构造函数开始,应初始化所有内容。尽快初始化变量非常重要:

    darr() {
        start = nullptr;
        end = nullptr;
        elemc = 0;
        size = 0;
    }

现在让我们看一下方法add。应该怎么办?在容器中添加一个元素,并保留现有元素。现在正在做什么?让我们看看:

  1. 创建临时void*指针。
void* end_temp = 0;
  1. [检查是否为end != nullptr,我们将end分配给end_temp
if (this->end) { end_temp = this->end; }
  1. 分配内存并增加elemc(我认为是元素计数)
if (true == this->alloc(++this->elemc))
  1. 下一个?我不确定。我也不确定这与将元素添加到容器中的简单任务有什么关系:
{
     end_temp = this->end;

            for (int i = 0; i <= sizeof(obj); ++i)
            {
                *(unsigned long*)((unsigned long)(end_temp)+i) = *(unsigned long*)((unsigned long)(&obj) + i);
            }
        }

        return true;
    }

让我们简化并做我们想要的,即添加元素:

        if (true == this->alloc())
        {
            start[size] = obj;
            this->size++;
        }

alloc()不再接受参数,因为它总是增加1。size是容器中元素的数量。我们只是将元素分配给最后一个索引,然后将大小增加1。

现在让我们看看get()。它需要做什么?在索引处获取元素。让我们简单地写:

T get(int i) const
{
    if (i < size)
        return start[i];
}
© www.soinside.com 2019 - 2024. All rights reserved.