【问题标题】:Why does nothing happen after instantiation? (C++ memory allocator implementation)为什么实例化后什么都没有发生? (C++ 内存分配器实现)
【发布时间】:2019-11-27 14:41:37
【问题描述】:

对于我最近上的一门 C++ 课程来说,这是一个相当奇怪的作业。这个想法是使用双向链表在 C++ 中实现一个简单的内存分配器。我的 C++ 仅限于解决 Codeforces 上的问题,所以我不知道为什么似乎什么都没有打印出来。代码如下:

ma​​in.cpp

#include <iostream>
#include "tests.h"

int main() {
    Tests tests = Tests();
    tests.run();

    return 0;
}

allocator.cpp

#include <iostream>
#include "allocator.h"

void* CleverPtr::get() const {
    return data;
}

Allocator::Allocator() {

    Allocator(100);//100 Bite
}

Allocator::Allocator(size_t size) {

    memory = (char*)malloc(size);

    head->next = nullptr;
    head->prev = nullptr;
    head->size = size;
    head->block = memory;
    head->state = FREE;
}

CleverPtr Allocator::alloc(size_t size) {

    dl_l *ptr = head;
    bool find = false;

    while (ptr){
        if (ptr->state == FREE and ptr->size >= size) {
            find = true;
            break;
        }
        ptr = ptr->next;
    }

    if (find) {
        dl_l new_block;
        new_block.next = nullptr;
        new_block.prev = nullptr;
        new_block.block = ptr->block;
        new_block.size = size;
        new_block.state = OCCUPIED;

        ptr->block = (char*)((uintptr_t)(ptr->block) + size);

        add_to_list(ptr->prev, &new_block, ptr);

        return CleverPtr(new_block.block);
    }

    return CleverPtr(nullptr);
}
void Allocator::free(CleverPtr &ptr) {
    dl_l * node = (dl_l*)((char *)ptr.get() - offsetof(dl_l, block));

    node->state = FREE;
}

void Allocator::defrag() {
    dl_l *ptr = head;

    while(ptr) {
        if (ptr->next) {
            if (ptr->state == FREE and ptr->next->state == FREE) {
                ptr->size += ptr->next->size;
                remove_from_list(ptr->next);
            }
        }
        ptr = ptr->next;
    }
}

std::list<dl_l*> Allocator::show_busy_blocks() const {
    dl_l *ptr = head;

    std::list<dl_l*> busy_blocks = std::list<dl_l*>();

    while(ptr) {
        if (ptr->state == OCCUPIED) {
            busy_blocks.push_back(ptr);
        }
        ptr = ptr->next;
    }

    return busy_blocks;
}

std::list<dl_l*> Allocator::show_free_blocks() const {
    dl_l *ptr = head;

    std::list<dl_l*> free_blocks = std::list<dl_l*>();

    while(ptr) {
        if (ptr->state == FREE) {
            free_blocks.push_back(ptr);
        }
        ptr = ptr->next;
    }

    return free_blocks;
}

tests.cpp

#include <cassert>
#include "tests.h"


void Tests::run() {

    Allocator allocator = Allocator(100);

    //CleverPtr ptr = allocator.alloc(10);

    //std::list<dl_l*> busy_blocks = allocator.show_busy_blocks();

    //assert(busy_blocks.size()==1);
    cout << "Test 1" << endl;

    //CleverPtr ptr1 = allocator.alloc(10);
   // std::list<dl_l*> busy_blocks1 = allocator.show_busy_blocks();
    //assert(busy_blocks1.size()==2);
    cout << "Test 2" << endl;

   // CleverPtr ptr2 = allocator.alloc(10);
   // std::list<dl_l*> busy_blocks2 = allocator.show_busy_blocks();
    //assert(busy_blocks2.size()==3);
    cout << "Test 3" << endl;

   // allocator.free(ptr1);
    //std::list<dl_l*> free_blocks = allocator.show_free_blocks();
    //assert(free_blocks.size()==2);
    cout << "Test 4" << endl;

    //allocator.free(ptr2);
    //std::list<dl_l*> free_blocks1 = allocator.show_free_blocks();
   // assert(free_blocks1.size()==3);
    cout << "Test 5" << endl;

    //allocator.defrag();
    //std::list<dl_l*> free_blocks2 = allocator.show_free_blocks();
    //assert(free_blocks1.size()==1);
    cout << "Test 6" << endl;

    cout << "Tests done successfully" << endl;
}

allocator.h

#include <algorithm>
#include <iostream>
#include <list>
#include <cstdio>
#include "dl_list.h"

#ifndef ALLOCATORLT_ALLOCATOR_H
#define ALLOCATORLT_ALLOCATOR_H

typedef struct{
    int* offset;
    int size;
} block;

using namespace std;

class CleverPtr {
    void* data;

public:
    void* get() const;
    explicit CleverPtr(void* data): data(data){}
};

class Allocator {
    private:
        char* memory;
        dl_l* head;



    public:
        Allocator();
        explicit Allocator(size_t size);

        std::list<dl_l*> show_busy_blocks() const;
        std::list<dl_l*> show_free_blocks() const;

        CleverPtr alloc(size_t size);
        void free(CleverPtr&);
        void defrag();
};


#endif //ALLOCATORLT_ALLOCATOR_H

dl_list.h

#include <cstdint>

#ifndef ALLOCATORLT_LIST_H
#define ALLOCATORLT_LIST_H

#endif //ALLOCATORLT_LIST_H
enum STATES {FREE, OCCUPIED};

typedef struct dl_list {
    struct dl_list *next;
    struct dl_list *prev;
    int size;
    char * block;
    int state;
} dl_l;

static void add_to_list(dl_l *prev_node, dl_l *new_node, dl_l *next_node) {
    if (prev_node) {
        prev_node->next = new_node;
        new_node->prev = prev_node;
    }

    if (next_node) {
        next_node->prev = new_node;
        new_node->next = next_node;
    }
}

static void remove_from_list(dl_l *node) {
    if (node->prev)
        node->prev->next = node->next;

    if (node->next)
        node->next->prev = node->prev;
}

tests.h

#include "allocator.h"

#ifndef ALLOCATORLT_TESTS_H
#define ALLOCATORLT_TESTS_H


class Tests {

public:
    void run();
};


#endif //ALLOCATORLT_TESTS_H

我必须插入所有代码才能复制问题。如您所见,我注释掉了tests.cpp 中的所有代码行,因为它们对输出没有任何影响。

Allocator allocator = Allocator(100); 行之后的所有couts 都被忽略,这意味着该构造函数调用有问题。不过,我不知道到底是什么。

有人可以帮我解决这个问题吗?

附:如果您碰巧注意到任何其他错误或严重错误(我怀疑有一些),请告诉我。谢谢

【问题讨论】:

  • Allocator::Allocator() { Allocator(100); } 不会做你期望它做的事情:它创建一个临时的,在离开构造函数后立即被销毁 - 并使你的构造对象未初始化。您很可能想要构造函数委托:Allocator() : Allocator(100) { }
  • Allocator::Allocator 取消引用 head 指针而不对其进行初始化。
  • 如果您碰巧注意到任何其他错误或严重错误 好吧,除非这是一个错字Allocator::Allocator() { Allocator(100); },否则如果您打算这样做,则永远不应该写一些高级的东西,比如创建一个分配器。
  • dl_l new_block; /* ... */ add_to_list(ptr-&gt;prev, &amp;new_block, ptr); – 添加一个指向局部变量的指针,该变量将在退出函数时被销毁 – 在列表中留下一个悬空指针...
  • @OP -- 为什么我的印象是你正在尝试使用另一种语言(可能是 Java)作为指导来编写 C++?这永远不会成功。

标签: c++ memory memory-management allocator


【解决方案1】:

您从不为head 赋值,但您在构造函数中使用head-&gt;next = nullptr; 取消引用它。很可能,head 是NULL 或指向垃圾,当您尝试访问next 指针时会导致错误。

看看这段代码:

Allocator::Allocator(size_t size) {

    memory = (char*)malloc(size);

    head->next = nullptr;
    head->prev = nullptr;
    head->size = size;
    head->block = memory;
    head->state = FREE;
}

您根本没有设置head 指向任何东西。你觉得head-&gt;next在这里是什么?

我怀疑你的意思是:

Allocator::Allocator(size_t size) {
    head = NULL;
}

没有理由在这里分配一个块,因为没有人想要一个指向块的指针。

【讨论】:

  • 这是未定义的行为,malloc 不会产生一个有效的对象,所以你实际上需要在使用它之前做一个放置 new。
  • 最好为dl_list 编写一个构造函数并在那里设置成员。那么我们只需要head = new dl_list();
  • @DavidSchwartz,请您在回答中详细说明一下。我添加了head = NULL 行,但仍然没有输出。
  • 为什么要在构造函数中分配块?没有人要求阻止。您是否出于某种原因只想从一个空闲块开始?如果是这样,为什么不调用分配块的代码而不是重复逻辑?
  • @DavidSchwartz,我想回答这些问题需要比我目前拥有的更多的 C++ 知识。因此,除非要求向我提供错误和解决方法是一种选择,否则我将不得不花一些时间学习 C++ 以获得正确的理解。
猜你喜欢
  • 1970-01-01
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2011-03-01
相关资源
最近更新 更多