如果通过重载`new []`分配给`malloc`来分配`free`内存是否安全?

时间:2015-04-23 16:45:22

标签: c++ c++11 memory memory-management

我的问题不是Is it safe to `free()` memory allocated by `new`?的重复。

我正在为POD编写一个玩具垃圾收集器,我正在定义自己的自定义operator new/new[]operator delete/delete[]。代码如下:

#include <iostream>
#include <map>

std::map<void*, std::size_t> memory; // globally allocated memory map
struct collect_t {} collect; // tag for placement new

void* operator new(std::size_t size, const collect_t&)
{
    void* addr = malloc(size);
    memory[addr] = size;
    return addr;
}

void* operator new[](std::size_t size, const collect_t&) 
{
    return operator new(size, collect);
}

void operator delete(void *p, const collect_t&) noexcept
{
    memory.erase(p); // should call ::operator delete, no recursion
    free(p);
}

void operator delete[](void *p, const collect_t&) noexcept
{
    operator delete(p, collect);
}

void display_memory()
{
    std::cout << "Allocated heap memory: " << std::endl;
    for (auto && elem : memory)
    {
        std::cout << "\tADDR: " << elem.first << " "
                  << "SIZE: "  << elem.second << std::endl;
    }
}

void clear()
{
    for (auto && elem : memory)
        free(elem.first); // is this safe for arrays?
    memory.clear();
}

int main()
{
    // use the garbage collector
    char *c = new(collect) char; 
    int *p = new(collect) int[1024]; // true size: sizeof(int)*1024 + y (unknown overhead)

    display_memory();
    clear();
    display_memory();
}

这个想法很简单:我将所有已分配的跟踪地址(使用我的自定义new分配的地址)存储在std::map中,并确保在一天结束时清除所有内存我的clear()功能。我为newdelete使用了一个标记(并且不会重载全局的标记),以便std::map的分配器可以调用全局的标记而不会重复出现。

我的问题如下:在我的clear()函数中,我在行中取消分配内存

for (auto && elem : memory)
    free(elem.first); // is this safe for arrays?

这对阵列是否安全,例如对于int *p = new(collect) int[1024];?我相信它是,因为void* operator new[](std::size_t size, const collect_t&)调用operator new(size, collect);,后者调用malloc。我不是百分百肯定的,这里可能会出问题吗?

2 个答案:

答案 0 :(得分:2)

在我看来,为了让内存位于您的memory容器中,必须已分配始终调用的自定义分配器{{ 1}}。因此,我相信你的免费代码应该没问题。

显然,如果有人将随机地址填充到内存映射中,您将会遇到各种未定义的行为。

答案 1 :(得分:1)

假设使用垃圾收集器的对象永远不会实现析构函数,并且这适用于这些对象可能包含的任何成员,代码本身就是&#34;安全&#34;从某种意义上来说,对free()的直接调用就是绕过编译器所做的工作,以实现与内联delete调用相同的工作。

但是, 代码不是很安全

如果你曾经改变了垃圾收集器的工作方式,或者new函数的工作方式,那么你必须找到所有直接调用free()来解决任何问题。如果代码在垃圾收集器之外的上下文中被剪切和粘贴或重复使用,您将面临类似的问题。

最好始终将newdeletemallocfree进行匹配。