有效地生成字节缓冲区而不会破坏严格的别名

时间:2017-10-26 17:05:44

标签: c++ dynamic-allocation strict-aliasing

这是一个如此简单的模式,必须有一个很好的"整理出来的方式。

我有一个函数需要生成一个包含算术数据的动态大小的字节数组。

// 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的堆缺乏也无法解决这里需要做的事情:see on godbolt

在最糟糕的情况下,我可以将dispatch()作为模板,但这会变得非常混乱,我很想知道是否有办法摆脱这种混乱我忽略了反正。

谢谢!

编辑:我想到了一个想法(当然是在发布问题后立即......):我可以将real_data视为一个分配池而就地新算术最重要的数据:

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));
}

这看起来很时髦,但我认为&#34;这可能是合法的。可能?

1 个答案:

答案 0 :(得分:2)

解决别名规则的最安全方法是使用memcpy(),但您不需要在整个第二个数据副本上执行此操作。我建议您对本地float变量进行所有float工作,然后memcpy()real_data缓冲区放在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)); } 缓冲区中的适当位置。大多数编译器都会根据我的经验有效地优化它。

@Entity
@Table(name="OBJECTSTERMIC")
public class TermicObject {

    @Id
    @Column(name="TERMICID")
    private long termicId;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="OBJECTID",columnDefinition="INTEGER")
    private Object object;

    @Column(name="CONTECA_RIF")
    private int contecaRif;

    @Column(name="CONTECA_VAL")
    private int contecaVal;

    @Column(name="TYPE")
    private String type;

//getters and setters