19

我有一个混合的 C/C++ 程序。它包含一个针对 C 的 flex/bison 解析器,而其余部分是 C++。

作为 C 语言,生成的解析器和扫描器使用mallocrealloc和来管理它们的内存free。它们足以暴露钩子,允许我提交我自己的这些函数的实现。如您所料,(C++)程序的其余部分“想要”使用new,delete等。

做一点研究似乎表明相关标准并不能保证这种混合应该有效。特别是 C“堆”不一定是 C++“空闲区域”。看来这两个方案可以互相践踏。

最重要的是,有一天(很快)这个程序可能想要集成一个定制的堆实现,比如tcmalloc,C 和 C++ 都使用。

在这里做什么是“正确的”?

考虑到集成 tcmalloc(它解释了如何与 C 程序链接)的愿望,我很想在 C++ 内存管理中找到一些跨类型、跨线程、跨所有内容的重载/挂钩/任何东西。有了它,我可以将所有 C++ 分配/释放调用指向它们的 C 等价物(这反过来又落在 tcmalloc 上。)

这样的泛银河全球 C++ 钩子是否存在?可能它已经在做我想做的事了,类似于ios_base::sync_with_stdio默认情况下如何秘密地结合 iostream 和 stdio?

我对讨论 stdio 与 iostream 不感兴趣,也不对切换解析器生成器或使用 C++ flex/bison 骨架(它们引入了独立的头痛)感兴趣。

编辑:请包括支持您的答案的 C++ 标准部分的名称。

4

3 回答 3

29

该标准确实保证混合两种分配变体将起作用。它不允许的是诸如调用free来自的内存之类的事情new,因为它们可能对这两种类型使用完全不同的竞技场。

如果你记得为给定的内存块调用正确的释放函数,你会没事的。如果您遵守规则,他们不会互相践踏,如果您不遵守规则,那么从技术上讲,您正在践踏,而不是他们:-)


C++11 标准的控制部分是如下20.6.13 C library声明:

  • 函数callocmalloc和是根据 C 标准提供的freerealloc
  • 函数不使用::operator new()or ::operator delete()
  • 这允许传统 C 的东西使用与普通 C++ 内存分配不同的内存领域。

鉴于您最终提出的建议,第二个要点很有趣,tcmalloc它取代了 C 传统函数并让 C++ 也使用它。

标准中有一个脚注解释了为什么他们不使用 let malloc()call ::operator new()

目的是通过调用 std::malloc() 或 std::calloc() 来实现 operator new()。换句话说,他们想要避免循环依赖。

但是,虽然它允许 operator new()调用malloc(),但我不确定标准是否真的需要它。因此,为了安全起见,您可能希望同时注入tcmallocCC++ 领域。

您已经表明您已经知道如何为 C 执行此操作。对于 C++,只需在代码中提供整套全局operator new()/delete()函数即可完成,并适当地编写为tcmalloc在幕后调用。C++ 标准规定3.7.4 Dynamic storage duration

该库为全局分配和释放函数提供默认定义。一些全局分配和释放函数是可替换的。

C++ 程序应最多提供一个可替换分配或解除分配函数的定义。任何此类函数定义都会替换库中提供的默认版本。

以下分配和释放函数在程序的每个翻译单元的全局范围内隐式声明:

  • void* operator new(std::size_t);
  • void* operator new[](std::size_t);
  • void operator delete(void*);
  • void operator delete[](void*);
于 2012-12-02T22:00:35.387 回答
2

行。挖出该标准的旧工作草案(2/28/2011 rev 3242。)似乎相关部分是3.7.4 Dynamic storage duration18.6.1 Storage allocation and deallocation

简而言之,我想要的泛银河钩子似乎是全局 new 和 delete 运算符本身。如果一个人尊重某些语义(在3.7.4.1and 3.7.4.2: 基本上根据需要委托给new_handler)一个人被允许替换

void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);

阻止整个 C++ 程序的默认内存管理。我仍然找不到证明@paxdiablo 正确的部分,但我愿意暂时使用它。

于 2012-12-02T22:54:26.217 回答
-2

您不必担心 Flex 或 Bison 生成的代码分配的任何内存;他们自己处理。其余的,只需使用newand delete。(并且 Flex 和 Bison 能够生成某种 C++。总的来说,我发现通过一个简单的脚本运行输出,使用sed足以使它们的输出真正与 C++ 兼容。)

于 2012-12-02T22:21:57.800 回答