裸机,无需全球运营商新
Bare metal without global operator new
考虑安全软件,其中一般不允许动态分配,不允许例外。仅当类显式定义运算符new
和delete
时,才允许动态分配。对其他类使用运算符new
应该会导致编译失败。
在所述情况下导致编译失败的最简单方法是删除全局新运算符:
void* operator new(std::size_t) = delete;
一方面,这会导致标准库的副作用。例如,包含<array>
通过<stdexcept>
将包含传播到<new_allocator>
。<new_allocator>
使用运算符::new
这会导致生成失败,即使你不想使用异常和内存分配。根据Scoot Meyers的说法<array>
应该是裸机友好的。
另一方面,这会导致编译器内置运算符出错
src/main.cpp:91:31: error: deleted definition of 'void* operator new(std::size_t)'
void* operator new(std::size_t) = delete; ^
<built-in>: note: previous declaration of 'void* operator new(std::size_t)'
有什么解决方案可以禁止::new
并使用<array>
吗?
是否有任何解决方案可以在全球范围内禁止::new
?
如果你使用GCC和GNU LD,那么我认为你可以在你的链接器标志中添加--wrap=malloc
。由于全局::new
在内部使用malloc()
,因此应用程序中对malloc()
的所有调用都将替换为__wrap_malloc()
。如果未定义此函数,则链接将失败。
另一个可能更简单的选择是将ASSERT(DEFINED(malloc) == 0, "Dynamic allocation used!");
添加到链接器脚本中。这将断言未定义malloc()
。
这两个选项都不保护您重新定义全局::new
以使用某种其他形式的全局分配。您可以在链接器脚本中对全局符号::new
执行相同的操作,但是它的名称被破坏了(在此处_Znwj
),所以这会有点奇怪......
不管你使用什么编程语言:
在任何有声的裸机系统上,只需从链接器脚本中完全删除.heap
段即可。然后,任何依赖于动态分配的代码都将无法链接。而且,您不必为无论如何都不打算使用的段分配RAM。
我想强调两件事:
如果异常没有- 进入代码,则包含与异常相关的标头及其定义不应打扰您。
- 禁用异常时,无法在代码中使用它们(如果禁用,编译将失败)。但是,它不会从标准库中删除异常的使用。标准库可能包含模板类的预编译版本,例如
std::string
(即std::basic_string<char, ...>
) 或std::streambuf
(即std::basic_streambuf<char, ...>
),当您在代码中使用它时,编译器不会尝试实例化模板,它只是重用预编译的版本,但有例外。
为了更好地控制您的代码,我强烈建议使用 G++ 编译器-nostdlib
编译选项完全排除标准库。它不会阻止您使用各种模板类,例如 STL 中的std::array
,它只会为您排除整个C++库和运行时。
我还建议阅读裸机C++实用指南。它可能会更深入地了解C++裸机内部结构。
- 呼叫运营商<<临时
- 两个运营商的一些奇怪的冲突<<
- 如何在 CPP 中访问家长的运营商
- 如何明确调用好友流运营商
- 私有运营商删除会触发 GCC 和 Clang 的编译时错误,但不会在 MSVC 上触发编译时错误
- 使用运营商New分配的数据结构是否有任何副作用
- "Inheriting"移动运营商?
- 朋友ostream&运营商<<无法访问私人会员
- 为什么在下面的代码返回类型中是用于运营商重载的类类型
- 范围的枚举(枚举类)关系运营商
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 对这两个分配运营商之间的不同感到困惑
- 我的班级意外加法运营商
- OpenACC - C++"新"运营商问题
- c 对运营商的一致性是新的,有多少重要
- 为什么我不能使私人运营商成为新的并使用默认实现?
- 全球取代所有新运营商
- 包装C 朋友在Cython中的非会员运营商
- 合法的交换运营商的模板实施
- 裸机,无需全球运营商新