【问题标题】:Unable to delete pointer on heap memory无法删除堆内存上的指针
【发布时间】:2020-03-30 02:11:05
【问题描述】:

我正在用 C++ 制作自己的动态分配器。但是我遇到了一个问题,我无法释放我的记忆。 这是Test.cpp的代码:

#include "Memory/MemoryManager.h"

int main(){
    initMemory(1);
    int* p = allocate<int>();
    int* q = allocate<int>();
    int* r = allocate<int>();
    cout<<p<<endl;
    cout<<q<<endl;
    cout<<r<<endl;
    freeAddress<int>(q);
    return 0;
}

MemoryManager.h:

#ifndef MEMORY_MANAGER_INCLUDED
#define MEMORY_MANAGER_INCLUDED

#include <iostream>
#include <map>
#include <memory>

using namespace std;

char* memory;
char* current;

map<void*, size_t> freePointers;

void initMemory(size_t size){
    memory = (char*)malloc(size);
    current = memory;
}

template<typename T> T* allocate(){
    T* address = NULL;
    for (auto p : freePointers){
        if (p.second == sizeof(T)){
            address = static_cast<T*>(p.first);
        }
    }

    if (address == NULL){
        address = new(current) T();
        current += sizeof(T);
    }

    return address;
}

template<typename T> T* allocate(size_t size){
    T* address = NULL;
    for (auto p : freePointers){
        if (p.second == sizeof(T) * size){
            return static_cast<T*>(p.first);
        }
    }

    if (address == NULL){
        address = new(current) T[size];
        current += sizeof(T) * size;
    }
    return address;
}

template<typename T> void freeAddress(T* address){
    freePointers.insert({(void*)address, sizeof(*address)});
    delete address;
}

template<typename T> void freeAddress(T* address, size_t size){
    freePointers.insert({(void*)address, sizeof(*address) * size});
    delete [] address;
}
#endif

输出:

0x55ee37729e70
0x55ee37729e74
0x55ee37729e78
0x55ee37729e70
0x55ee37729e78
free(): invalid pointer

我知道我不能删除堆栈内存上的指针,但我根本没有使用它。另外请指出我做错了什么或性能费用。请帮忙。

【问题讨论】:

    标签: c++ pointers heap-memory dynamic-memory-allocation delete-operator


    【解决方案1】:

    您使用malloc 分配了一大块内存,然后在某个指向已分配内存的指针上调用delete

    在您的代码中,q(memory + sizeof(int))。该指针从未被分配返回,因此无法释放。这就是错误的原因。

    此外,mallocdelete 不匹配是未定义的行为。您应该改为在原始 memory 指针上调用 free() 作为最后的清理,并且永远不要在单个值上调用 delete

    如果要调用freeAddress 中的析构函数,请使用address-&gt;~T();

    【讨论】:

      【解决方案2】:

      您在 initMemory() 中分配了一个 1 字节的内存块。您正在使用malloc() 进行该分配,因此当您完成使用它时,必须使用free() 释放内存块,但您没有这样做。

      您的freeAddress()delete'ing 内存,从未使用new 分配。在allocate() 内部,您使用的是placement-new 而不是new,它们不是一回事。当你使用 placement-new 时,你必须手动调用对象的析构函数,而不是 free()delete 它。

      而且您当然不希望释放稍后将重用的内存。这违背了缓存“释放”内存的全部目的。

      new[] 使用的内存比您请求的要多,因此它可以为delete[] 存储信息,以了解要释放多少元素以及如何释放它们。您不会知道有多少额外开销,因为它是由实现定义的。所以在这种情况下使用new[]是不安全的。

      试试类似的东西

      #include "Memory/MemoryManager.h"
      
      int main(){
          initMemory(sizeof(int) * 3);
          int* p = allocate<int>();
          int* q = allocate<int>();
          int* r = allocate<int>();
          cout << p << endl;
          cout << q << endl;
          cout << r << endl;
          freeAddress<int>(q);
          doneMemory();
          return 0;
      }
      
      #ifndef MEMORY_MANAGER_INCLUDED
      #define MEMORY_MANAGER_INCLUDED
      
      #include <iostream>
      #include <map>
      #include <memory>
      
      char* memory;
      char* current;
      size_t available;
      std::map<void*, size_t> freePointers;
      
      void initMemory(size_t size){
          memory = (char*) malloc(size);
          current = memory;
          available = (memory) ? size : 0;
      }
      
      void doneMemory(){
          freePointers.clear();
          free(memory);
          memory = current = nullptr;
          available = 0;
      }
      
      template<typename T>
      T* allocate(){
          T *address = nullptr;
      
          for (auto iter = freePointers.begin(); iter != freePointers.end(); ++iter){
              if (iter->second == sizeof(T)){
                  address = static_cast<T*>(iter->first);
                  freePointers.erase(iter);
                  break;
              }
          }
      
          if (!address){
              if (available < sizeof(T)){
                  return nullptr;
              }
              address = static_cast<T*>(current);
              current += sizeof(T);
              available -= sizeof(T);
          }
      
          return new(address) T();
      }
      
      template<typename T>
      T* allocate(size_t count){
          T *address = nullptr;
          size_t size = count * sizeof(T);
      
          for (auto iter = freePointers.begin(); iter != freePointers.end(); ++iter){
              if (iter->second == size){
                  address = static_cast<T*>(iter->first);
                  freePointers.erase(iter);
                  break;
              }
          }
      
          if (!address){
              if (available < size){
                  return nullptr;
              }
              address = static_cast<T*>(current);
              current += size;
              available -= size;
          }
      
          for(size_t i = 0; i < count; ++i)
              new(address+i) T();
          }
      
          return address;
      }
      
      template<typename T>
      void freeAddress(T* address){
          address->~T();
          freePointers.insert({(void*)address, sizeof(T)});
      }
      
      template<typename T>
      void freeAddress(T* address, size_t count){
          for (size_t i = 0; i < count; ++i)
              address[i].~T();
          freePointers.insert({(void*)address, sizeof(T) * count});
      }
      
      #endif
      

      话虽如此,这不是一个非常安全或强大的内存分配器,但它应该可以帮助您入门。

      如果您真的想创建自定义内存分配器,您应该编写一个遵循Allocator 策略的类,然后您可以将该分配器与标准 C++ 容器一起使用,例如std::vector。让编译器和标准库为您处理大部分繁重的工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-30
        • 2015-11-27
        • 1970-01-01
        • 2019-03-31
        • 2020-03-09
        • 2017-03-01
        • 2019-09-17
        • 2012-08-05
        相关资源
        最近更新 更多