【问题标题】:Implementing C realloc in a macro with new and delete使用 new 和 delete 在宏中实现 C realloc
【发布时间】: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 库函数。否则,您将需要更改调用以存储分配的大小并在其后返回一个指针。这本质上是内存管理器在内部执行的操作,因此您正在重复行为(浪费内存)。 newdelete 不是 mallocfree 的直接替代品,也没有 realloc 等效项。
  • 我认为没有一种可移植的方式来从指针获取分配大小,您需要将这些信息保留在一边,也许通过在分配内存的开头插入额外的数据,这将保持分配数据的大小。或者您可以编写自己的分配器来跟踪其所有分配,然后将其公开给库。
  • @paddy - 啊,我知道。尽管我喜欢它在更多情况下的行为,但我尝试避免使用 malloc,因为将它与新分配混合是错误的真正来源,并且使用 new 是不可避免的。我想我应该接受将两者混合并善于配对正确的分配/释放调用
  • @G.M.我想通过尽可能不干扰地更改库来避免需要包装分配,只是为了“人体工程学”。然后遇到了一个让我比什么都好奇的障碍,如果这甚至可以做到。
  • 像你所做的那样,调查这个并发现问题是没有问题的。结果是您提出了一个公平的问题并获得了一些反馈。这可能不是您所期望的反馈,但这是您拓宽视野的方式。

标签: c++ macros new-operator realloc


【解决方案1】:

TL;DR - 无法完成,保持代码不变。

C++ 中没有realloc 的可能性。 realloc 违背了 C++ 面向对象的本质,因为对象不能像那样移动,所以 C++ 彻底否定了这个想法。

也不能用newdelete来实现,因为你需要知道当前数组的大小来复制数据,这是不可能的(以可移植的方式),更不用说效率低下每次都必须复制东西(realloc 在许多情况下可以就地工作)。

好消息是,在 C++ 程序中使用 mallocreallocfree 分配原始内存没有任何问题。还有内置的newdelete 在很多情况下委托给mallocfree,所以真的没有问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 2017-12-07
    相关资源
    最近更新 更多