代码之家  ›  专栏  ›  技术社区  ›  Mooing Duck

在放置新数据之前初始化数据是未定义的行为吗?

  •  1
  • Mooing Duck  · 技术社区  · 7 年前
    struct A { //POD class
        char data[10];
        void print() {std::cout << data;}
    };
    int main() {
        char buffer[11] = "HELLO"; //sets values in buffer
        A* a = new(buffer)A;
        a->print(); // read from memory buffer
        a->~A();
    }
    

    从类的角度来看,这是从未初始化的内存读取,但从内存的角度来看,内存实际上是初始化的。这是一种未定义的行为,还是仅仅是危险的行为?

    new(buffer)A and a->~A() ,这称为“placement new”,用于在内存中的特定缓冲区中构造对象。这是 vector

    3 回复  |  直到 7 年前
        1
  •  8
  •   Michael Kenzel    7 年前

    即使在这种特殊情况下,类成员和数组保证具有相同的地址(基于 [basic.compound]/4.3 再加上 requirements on new-expression s 除了将对象放在缓冲区的开头之外,不允许编译器执行任何操作),我很确定这是未定义的行为。

    我相信相关的标准是 basic.memobj §1 :

    mem初始化器 对于构造函数中的成员,类中也没有默认的初始值设定项,因此,该成员将被默认初始化 [class.base.init/9.3] no initialization will be performed for them basic.indet §2 适用于数组内容的任何使用(在 operator <<

    如果评估产生不确定值,则行为未定义,以下情况除外[]

        2
  •  2
  •   Yakk - Adam Nevraumont    7 年前

    构造对象后缓冲区的状态未定义。编译器可以自由编写 "format c;:" A . 它们还可以自由地优化缓冲区的预加载,只需丢弃您在该行中所做的操作。

    print 然后将代码作为 << 需要以nul结尾的缓冲区。

        3
  •  1
  •   supercat    7 年前

    显然,自从placement new首次标准化以来的几十年中,编译器的理念发生了变化,按位导入很有用,但编译器无法可靠地支持它的情况更为常见。一个合理的解决方案是添加两种新的语法形式——一种是要求编译器导入位模式,另一种是明确声明位模式不重要——因为程序员可能比编译器编写者更了解位模式是否重要。然而,到目前为止,这种情况还没有发生,使得像您这样的结构处于尴尬的状态,即某些实现可以有效地支持您的结构,而其他实现则不能有效地支持您的结构,并且没有任何好的方法来识别支持它们的实现。