使用new char []或malloc的结果来表示浮动*是UB(严格别名冲突)吗?

gez*_*eza 13 c++ malloc strict-aliasing object-lifetime language-lawyer

哪些代码有UB(具体来说,哪些违反了严格的别名规则)?

void a() {
    std::vector<char> v(sizeof(float));
    float *f = reinterpret_cast<float *>(v.data());
    *f = 42;
}

void b() {
    char *a = new char[sizeof(float)];
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void c() {
    char *a = new char[sizeof(float)];
    float *f = new(a) float;
    *f = 42;
}

void d() {
    char *a = (char*)malloc(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void e() {
    char *a = (char*)operator new(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}
Run Code Online (Sandbox Code Playgroud)

我问这个,因为这个问题.

我认为,d没有UB(或者malloc在C++中没用).也正因为如此,它似乎是合乎逻辑,即b,ce 没有它的.我错了吗?也许b是UB,但c不是吗?

M.M*_*M.M 7

序言:存储对象是C++中的不同概念.存储是指存储空间,对象是具有生命周期的实体,可以在一个存储区中创建和销毁.随着时间的推移,存储可以重新用于托管多个对象.所有对象都需要存储,但可以存储没有对象的存储.


c是对的.Placement-new是在存储中创建对象的有效方法之一(C++ 14 [intro.object]/1),即使该存储中存在预先存在的对象.重新使用存储会隐藏地破坏旧对象,只要它们没有非平凡的析构函数([basic.life]/4),这就完全没问题了.在现有存储([expr.new]/1)中new(a) float;创建类型float和动态存储持续时间的对象.

de在当前对象模型规则中由于省略而未定义:通过glvalue表达式访问内存的效果仅在表达式引用对象时定义; 而不是当表达式引用不包含任何对象的存储时.(注意:请不要对现有定义明显不足的问题留下非建设性意见).

这并不意味着"malloc无用"; 效果mallocoperator new获得储存.然后,您可以在存储中创建对象并使用这些对象.事实上,这正是标准分配器和new表达式的工作原理.

ab是严格的别名冲突:类型的glvalue float用于访问不兼容类型的对象char.([basic.lval]/10)


有一种建议这将使所有的明确定义的情况下(比的取向其他一个提到下文):在该提案中,使用*f隐式地创建该类型中的位置的目的,用一些注意事项.


注意:在be的情况下没有对齐问题,因为new-expression并且::operator new保证为任何类型([new.delete.single]/1)正确地分配存储.

但是,在这种情况下std::vector<char>,即使标准指定::operator new要调用以获得存储,标准也不要求将第一个向量元素放在该存储的第一个字节中; 例如,向量可以决定在前面分配3个额外字节,并将其用于某些簿记.