将编译时常量向量转换为堆分配版本
Convert compile-time constant vector to heap-allocated version
我让Visual Studio的Code Analyzer变得疯狂。这一行:
void Foo() {
const std::vector<uint8_t> bar{ /* 21,140 uint8_t entries */ };
//...
}
发出 C6262 警告:
Function uses 21140 bytes of stack: exceeds /analyze:stacksize`16384`. Consider moving some data to heap
矢量包含二进制文件的各个字节。在这种情况下,我的全部意图是不使用外部文件,以便数据始终可供函数调用者使用。
有没有一种简单的方法可以将编译时值转换为堆分配的值?
将声明从函数中移出到静态文件级范围是非常昂贵和耗时的,因为 A( 内存永远不会被释放,B( 这只是大约十几个使用多个大型二进制数组的函数之一,重命名它们都不能很好地扩展。
忽略警告也是不可能的。
编辑:
MCRE 应要求。("CR"是有争议的,因为它是 300,000 LOC 游戏引擎的一部分,但这并不重要,因为 CA 在大矢量的基本声明中失败了......所以这是实际用法。正如ShadowRanger的回答评论中所述,既没有将大向量声明为static
也没有const static
解决问题,CA仍然发出警告:
std::unique_ptr<ShaderProgram> Renderer::CreateDefaultShaderProgram() noexcept {
static std::vector<uint8_t> g_VertexFunction{ /* 5K entries */ };
static std::vector<uint8_t> g_DefaultPixelFunction{ /* 21,140 entries */ };
// // Code Analysis warns here at g_DefaultPixelFunction declaration.
ShaderProgramDesc desc{};
desc.name = "__default";
desc.device = _rhi_device.get();
{
ID3D11VertexShader* vs = nullptr;
_rhi_device->GetDxDevice()->CreateVertexShader(g_VertexFunction.data(), g_VertexFunction.size(), nullptr, &vs);
ID3DBlob* blob = nullptr;
::D3DCreateBlob(g_VertexFunction.size(), &blob);
std::memcpy(blob->GetBufferPointer(), g_VertexFunction.data(), g_VertexFunction.size());
g_VertexFunction.clear();
g_VertexFunction.shrink_to_fit();
desc.vs = vs;
desc.vs_bytecode = blob;
desc.input_layout = _rhi_device->CreateInputLayoutFromByteCode(blob);
}
{
ID3D11PixelShader* ps = nullptr;
_rhi_device->GetDxDevice()->CreatePixelShader(g_DefaultPixelFunction.data(), g_DefaultPixelFunction.size(), nullptr, &ps);
ID3DBlob* blob = nullptr;
::D3DCreateBlob(g_DefaultPixelFunction.size(), &blob);
std::memcpy(blob->GetBufferPointer(), g_DefaultPixelFunction.data(), g_DefaultPixelFunction.size());
g_DefaultPixelFunction.clear();
g_DefaultPixelFunction.shrink_to_fit();
desc.ps = ps;
desc.ps_bytecode = blob;
}
return std::make_unique<ShaderProgram>(std::move(desc));
}
编辑2:
根据 Jeff Garrett 的回答,解决方案是事先将初始值设定项列表变量声明为静态(const 因为"Const all the Things!"(:
const static std::initializer_list<uint8_t> vs_init_list{/*5K entries*/};
std::vector<uint8_t> g_VertexFunction{vs_init_list};
const static std::initializer_list<uint8_t> ps_init_list{/*21K entries*/};
std::vector<uint8_t> g_PixelFunction{ps_init_list};
//... Same as before
如果您将它们留在原地并声明它们static
以及const
则不需要重命名;static
不需要移动到文件范围(这可能会有名称冲突的风险(,但只有在需要在多个函数之间共享文件范围时,才可以移动到文件范围。
内存使用应该不是问题;无论如何,初始值设定项都必须以某种方式存储在程序中,因此将其存储在static
范围内不是问题(它甚至可以通过从 mmap 编辑的二进制文件常量中读取来替换运行时分配和初始化来减少有效的程序内存使用量(。
向量的堆栈空间不依赖于其大小。
向量正在用 std::initializer_list 初始化。这就是需要潜在堆栈空间的原因。这就是你可以做静态的。
看看这是否有帮助。 它不会将数据移动到堆中,但会将其放在根本不需要运行时初始化的静态数据中。
void Foo() {
const uint8_t std::bar [] = { /* 21,140 uint8_t entries */ };
//...
}
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 导入库可以跨dll版本工作吗
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 获取字符串的长度并将其分配给数组
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 将地址分配给本地指针后,公共对象的变量将消失
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 我在二维向量中是否正确分配了内存
- 正在尝试重载二进制搜索树分配运算符
- GlobalAlloc而不是其他分配方法
- 将编译时常量向量转换为堆分配版本
- Visual Studio 版本之间的不同未分配内存行为
- 跨MSVCRT版本分配c++对象