在编译时强制执行静态存储
Enforce Static Storage at Compile-time
我有一个结构,我想在上面强制执行静态存储。这是DSP上的矢量类型,意外地在堆栈上声明它对用户来说是一个常见的错误,会导致堆栈溢出、性能问题或两者兼而有之。据我所知,这是不可能的,但我很好奇是否有其他人知道得更好。
示例用例:
static Vector64 v1; // OK
static Vector64 v2; // OK
static Vector64 result; // OK
result = v1 * v2; // OK
Vector64 v3; // I would like this to give a compile-time error
Vector64 v4;
result = v3 * v4;
我的编译器是Clang/LLVM3.2,编译器特定的属性是公平的。
由于C没有类,我几乎排除了这种可能性。
通常,在C++中,当您定义一个类时,您无法控制该类型的对象是在static
、堆栈上、堆上、const
还是不在const
、数组中定义,还是在另一个类的成员中定义。这些选项由类的用户决定。
有一些技巧可以让它远离堆(例如玩operator new
),或者只在堆上(例如使用生成器模式),但这不是你想要的
我很想看看这是怎么可能的,但在这个时候之前,我敢肯定你做不到。
如果您愿意接受运行时错误并深入实现,并且如果您的DSP有合适的地址布局,您可以简单地在Vector64的默认构造函数中插入this
的位置检查。
如果你提前知道地址空间,最安全的事情(从语言角度来看)就是简单地比较堆栈的绝对位置。
struct Vector64 {
Vector64() { assert( reinterpret_cast<uintptr_t>(this) < STACK_START ); }
};
风险更大但更灵活的定义可能是这样的:
__attribute__((noinline)) Vector64() {
int test;
assert( less<void*>()(this, &test) );
}
其中需要__attribute__((noinline))
来防止clang在Vector64对象之前对test
的分配进行排序(或者简单地在其他地方定义它)。从好的方面来看,重新排序优化不会导致此断言抛出误报,只会无声地失败。std::less
在这里也很重要,因为与<
不同,它明确允许在不同对象的地址之间进行比较。
这种方法非常糟糕,但通过干扰构建,这是在运行时通过确保不再构建堆栈来防止堆栈溢出的最佳机会。
如果你在C上编程,你会遇到问题。有了C++,它应该可以工作了。我从来没有用过那个编译器,但这两种语言在这方面有很大的不同。检查编译器。
- 如何为静态常量模板化专用整数值分配存储
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 具有静态存储持续时间的常量初始化变量的初始化顺序
- 静态存储类C++计数
- 如果静态变量只为程序的整个部分存储了一个副本,为什么我不能使用静态变量交换 2 个数字?
- 静态存储中的内联变量何时初始化?
- 静态存储持续时间初始化
- 线程上下文上的静态存储对象优化
- 在不同翻译单元中具有静态存储持续时间的依赖非局部常量浮点变量的常量初始化
- 什么是静态存储持续时间的临时对象
- 将对静态存储 cstyle 数组的引用从 constexpr 函数传递到另一个 constexpr 函数
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)
- 如何使用静态存储轻松生成符号列表
- 在编译时强制执行静态存储
- 具有静态存储持续时间的对象的C++级联破坏
- 消除具有静态存储时间的变量
- 初始化带有静态存储时间的std::数组,带有参数Pack扩展和附加值
- 是静态存储持续时间初始化为NULL或全零的对象中未初始化的指针
- 在main()之前初始化对象的静态存储持续时间
- 销毁静态存储持续时间对象和未定义的行为