【发布时间】:2021-07-17 09:24:47
【问题描述】:
我正在使用一个库,它可以让我覆盖它的一些宏,以了解它如何分配给堆
#define STBI_MALLOC(sz) malloc(sz)
#define STBI_REALLOC(p,newsz) realloc(p,newsz)
#define STBI_FREE(p) free(p)
我想接受一些分配到我的程序的堆而不包装它或过多担心它是如何分配的,通过使STBI_FREE() 宏与我通常如何释放此类内存的同义词,使用 @ 987654323@
#define STBI_MALLOC(sz) ((void*)new char[sz])
#define STBI_REALLOC(p,newsz) ???
#define STBI_FREE(p) (delete [](char*)(p))
不过,我不确定 STBI_REALLOC() 应该使用什么。如果我有以前的尺寸,我可以在多行中完成,但是......
// STBI_REALLOC(p,newsz)
if (newsz <= ???) { // don't know the allocation size
return p;
} else {
char * next = new char[newsz]
memcpy(next, p, ???); // don't know the allocaion size
delete [] (char*)p;
return (void*)next;
}
...如果不知道分配的大小,宏在库中接受的参数是不可能的。我有一个选项可以插入这个宏定义吗?
--- 编辑 ---
(接受的答案仍然有效,这超出了原始问题的范围,但我会附加这个以防使用同一库的任何人遇到它)
原来这个库有一个隐藏的预处理器部分用于这个确切的场景,如果库用户定义了STBI_REALLOC_SIZED(p,oldsz,newsz),库将改为使用它。
这允许我为图书馆定义以下绝对杰作:
#define STBI_MALLOC(sz) ((void*)(new char[sz]))
#define STBI_REALLOC_SIZED(p,oldsz,newsz) \
((newsz) <= (oldsz) ? (void*)(p) : [](void* lp, size_t loldsz, size_t lnewsz)->void*{char*n = new char[lnewsz]; memcpy(n, lp, loldsz); delete [] (char*)lp; return (void*)n;}(p, oldsz, newsz))
#define STBI_FREE(p) (delete [](char*)(p))
或者这个也很好用
#define REALLOC_SIZED(p,oldsz,newsz) \
((newsz) <= (oldsz) ? (void*)(p) : \
memcpy(new char[newsz], (void*)std::unique_ptr<char>((char*)(p)).get(), oldsz))
【问题讨论】:
-
首先,我想说这是个坏主意。如果它需要
realloc,那么您应该使用 C 库函数。否则,您将需要更改调用以存储分配的大小并在其后返回一个指针。这本质上是内存管理器在内部执行的操作,因此您正在重复行为(即浪费内存)。new和delete不是malloc和free的直接替代品,也没有realloc等效项。 -
我认为没有一种可移植的方式来从指针获取分配大小,您需要将这些信息保留在一边,也许通过在分配内存的开头插入额外的数据,这将保持分配数据的大小。或者您可以编写自己的分配器来跟踪其所有分配,然后将其公开给库。
-
@paddy - 啊,我知道。尽管我喜欢它在更多情况下的行为,但我尝试避免使用 malloc,因为将它与新分配混合是错误的真正来源,并且使用 new 是不可避免的。我想我应该接受将两者混合并善于配对正确的分配/释放调用
-
@G.M.我想通过尽可能不干扰地更改库来避免需要包装分配,只是为了“人体工程学”。然后遇到了一个让我比什么都好奇的障碍,如果这甚至可以做到。
-
像你所做的那样,调查这个并发现问题是没有问题的。结果是您提出了一个公平的问题并获得了一些反馈。这可能不是您所期望的反馈,但这是您拓宽视野的方式。
标签: c++ macros new-operator realloc