将编译时常量向量转换为堆分配版本
Convert compile-time constant vector to heap-allocated version
我把 Visual Studio 的代码分析器弄疯了。这一行:
void Foo() {
const std::vector<uint8_t> bar{ /* 21,140 uint8_t entries */ };
//...
}
发出 C6262 warning:
Function uses 21140 bytes of stack: exceeds /analyze:stacksize`16384`. Consider moving some data to heap
向量包含二进制文件的各个字节。在这种情况下,我的全部意图是不使用外部文件,以便函数调用者始终可以使用数据。
有没有一种简单的方法可以将编译时值转换为堆分配值?
将声明从函数移出到静态文件级作用域是非常昂贵和耗时的,因为 A) 内存永远不会被释放,并且 B) 这只是使用多个函数的十几个函数中的一个像这样的大型二进制数组并重命名它们并不能很好地扩展。
忽略警告也不行。
编辑:
MCRE 根据要求。 ("CR" 值得商榷,因为它是 300,000 LOC 游戏引擎的一部分,但这无关紧要,因为 CA 在基本声明过大向量时失败了……所以这里是实际用法。)在 的评论中陈述,既没有将大向量声明为 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:
根据,解决方案是预先将初始化列表变量声明为静态(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
看看这是否有帮助。它不会将数据移动到堆中,但会将其放入根本不需要运行时初始化的静态数据中。
void Foo() {
const uint8_t std::bar [] = { /* 21,140 uint8_t entries */ };
//...
}
如果您将它们留在原处并声明它们 static
以及 const
,则不需要重命名; static
不需要移动到文件范围(这会冒名称冲突的风险),只有在需要在多个函数之间共享它时才移动到文件范围。
内存使用应该不是问题;无论如何,初始化程序都必须以某种方式存储在程序中,因此将其存储在 static
范围内不是问题(它甚至可能通过从 mmap 读取替换运行时分配和初始化来减少有效的程序内存使用-ed 二进制文件常量).
矢量的堆栈 space 不取决于其大小。
矢量正在用 std::initializer_list 初始化。这就是需要潜在堆栈 space 的原因。这就是你可以做静态的。
我把 Visual Studio 的代码分析器弄疯了。这一行:
void Foo() {
const std::vector<uint8_t> bar{ /* 21,140 uint8_t entries */ };
//...
}
发出 C6262 warning:
Function uses 21140 bytes of stack: exceeds /analyze:stacksize`16384`. Consider moving some data to heap
向量包含二进制文件的各个字节。在这种情况下,我的全部意图是不使用外部文件,以便函数调用者始终可以使用数据。
有没有一种简单的方法可以将编译时值转换为堆分配值?
将声明从函数移出到静态文件级作用域是非常昂贵和耗时的,因为 A) 内存永远不会被释放,并且 B) 这只是使用多个函数的十几个函数中的一个像这样的大型二进制数组并重命名它们并不能很好地扩展。
忽略警告也不行。
编辑:
MCRE 根据要求。 ("CR" 值得商榷,因为它是 300,000 LOC 游戏引擎的一部分,但这无关紧要,因为 CA 在基本声明过大向量时失败了……所以这里是实际用法。)在 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:
根据
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
看看这是否有帮助。它不会将数据移动到堆中,但会将其放入根本不需要运行时初始化的静态数据中。
void Foo() {
const uint8_t std::bar [] = { /* 21,140 uint8_t entries */ };
//...
}
如果您将它们留在原处并声明它们 static
以及 const
,则不需要重命名; static
不需要移动到文件范围(这会冒名称冲突的风险),只有在需要在多个函数之间共享它时才移动到文件范围。
内存使用应该不是问题;无论如何,初始化程序都必须以某种方式存储在程序中,因此将其存储在 static
范围内不是问题(它甚至可能通过从 mmap 读取替换运行时分配和初始化来减少有效的程序内存使用-ed 二进制文件常量).
矢量的堆栈 space 不取决于其大小。
矢量正在用 std::initializer_list 初始化。这就是需要潜在堆栈 space 的原因。这就是你可以做静态的。