有效生成字节缓冲区而不会破坏严格的别名 [英] Efficiently generating byte buffer without breaking strict aliasing
问题描述
这是一个简单的模式,必须采用一种不错的方式进行分类。
This is such a simple pattern, there has to be a "nice" way of sorting it out.
我有一个需要生成动态尺寸的函数包含算术数据的字节数组。
I have a function that needs to generate a dynamically sized byte array containing arithmetic data.
// Given that I have a function that kinda looks like this:
void dispatch(std::vector<char> data); //Will take possesion of data.
// The behavior I want, but this breaks strict aliasing
void bad_foo(int c) {
std::vector<char> real_data(c * sizeof(float));
float* raw_data = reinterpret_cast<float*>(real_data.data());
//Fill raw_data with usefull stuff...
dispatch(std::move(real_data));
}
void correct_but_slow_foo(int c) {
std::vector<float> raw_data(c);
//Fill raw_data with usefull stuff...
std::vector<char> real_data(c * sizeof(float));
std::memcpy(real_data.data(), raw_data.data(), c * sizeof(float));
dispatch(std::move(real_data));
}
不幸的是,似乎连clang的堆清除都无法解决需要的东西可以在这里完成:在Godbolt上查看
Unfortunately, it seems even clang's heap elision is not managing to sort out what needs to be done here: see on godbolt
在最坏的情况下,我可以创建 dispatch()
模板,但这会变得非常混乱,我很想知道是否有解决办法
At the very worst, I can make dispatch()
a template, but that would become very messy, and I'm curious to see if there is a way out of this mess I'm overlooking anyways.
谢谢!
编辑:一个想法刚刚想到了这一点(立即发布了问题之后……):我可以将 real_data
视为分配池,并在其上放置新的算术数据:
A thought just crossed my mind (immediately after posting the question of course...) : I could treat real_data
as an allocation pool and in-place new the arithmetic data on top of it:
void fixed_foo(int c) {
std::vector<char> real_data(c * sizeof(float));
float* raw_data = new (real_data.data()) float[c];
//Fill raw_data with usefull stuff...
dispatch(std::move(real_data));
}
这看起来很像地狱,但我认为这可能是合法的。
This looks funky as hell, but I "think" it might be legal. Maybe?
推荐答案
避开别名规则的最安全方法是使用 memcpy()
,但您不需要对整个第二个数据副本执行此操作。我建议对本地 float
变量进行所有 float
工作,然后对 memcpy( )
一次将其存储到 real_data
缓冲区中的适当位置。根据我的经验,大多数编译器都会对此进行有效优化。
The safest way to get around aliasing rules is to use memcpy()
but you don't need to do that on a whole second copy of the data. I'd suggest doing all your float
work on a local float
variable and then memcpy()
ing that to the appropriate location in your real_data
buffer an element at a time. Most compilers will optimize that effectively in my experience.
void better_foo(int c) {
std::vector<char> real_data(c * sizeof(float));
//Fill raw_data with usefull stuff...
for (int i = 0; i < c; ++i) {
float x = my_complicated_calculation(i);
memcpy(&real_data[i * sizeof(float)], &x, sizeof(x));
}
dispatch(std::move(real_data));
}
这篇关于有效生成字节缓冲区而不会破坏严格的别名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!