将编译时常量向量转换为堆分配版本

Convert compile-time constant vector to heap-allocated version

本文关键字:分配 版本 转换 向量 编译 常量      更新时间:2023-10-16

我让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 */ };
//...
}