【问题标题】:Is it recommendable to use placement new when constructing an POD-object from a dynamically created array?从动态创建的数组构造 POD 对象时是否建议使用放置新?
【发布时间】:2011-11-04 16:30:54
【问题描述】:

对于任何 POD 类型,是否建议这样做:

any_pod* p = new any_pod[n];
for (std::size_t i = 0; i < n; ++i)
    new (&p[i].member) other_pod(whatever);

【问题讨论】:

  • 你为什么不直接做p[i].member = whatever;?保持简单,用一些没有优势的晦涩结构来迷惑每个人是没有意义的。
  • 您正在重新构建一个已经构建的对象,这似乎是一个不好的习惯(即使对于 POD 可能无害)。
  • @FrEEzE2046:如果它包含一个具有非平凡构造函数的对象,那么它不是一个 POD!因此,您所拥有的是未定义的行为,因为new 构造了对象,然后您在同一内存位置再次构造。
  • 代码是否正确取决于细节,但它绝对是一头丑陋、可怕的代码野兽。危险在于它完全掩盖了意图。如果您想要一个在某些私有内存中动态管理某些对象的类,您应该干净地设计它。这当然是可能的。如果您需要详细信息,请发布更多详细信息。
  • @KerrekSB:我不认为它依赖于对象,它是 UB,不管 UB 表现得有多糟糕。也就是说,如果member 有一个已经被调用的构造函数,那么在它之上的reconstructing 就是UB。这本身是否意味着系统将崩​​溃或只是重写内存中的某些值并且不会造成伤害,这都在 UB 所暗示的范围内

标签: c++ placement-new


【解决方案1】:

鉴于这个问题有点主观,不,我绝不会推荐这样的代码。不管它是否是未定义的行为,它仍然难以阅读,并且需要任何未来的维护者花额外的时间(也许很重要)来了解你在做什么。

如果您需要变量类型功能,请根据需要使用boost::variantboost::any

如果您只想从一个类中获取数据并将其复制/分配给另一个类,那就是转换构造函数和转换赋值运算符的用途。

【讨论】:

    【解决方案2】:

    通过在已经构建的对象之上进行构建,您违反了语言关于销毁的保证,因此无论该对象是否为 POD,我都不会这样做。

    我想知道你是不是想问一些稍微不同的问题:

    any_pod* p = reinterpret_cast<any_pod*>(malloc(n * sizeof(any_pod[n]));
    for (std::size_t i = 0; i < n; ++i)
      new (&p[i].member) other_pod(whatever);
    

    在这种情况下,您不是在重构,您只是在一块原始内存中构建。在这种情况下,放置 new 是合适的。 (尽管您必须编写这样的代码非常罕见。这是您在实现 std::vector 之类的东西时可能会做的事情。)一旦最后一个 pod 有,您必须非常小心地稍后释放数组被破坏了。

    【讨论】:

    • 您也可以使用标准的uninitialized_filluninitialized_copy 算法(在&lt;memory&gt; 中)来处理这类事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2016-07-05
    • 2023-03-29
    • 1970-01-01
    • 2017-01-28
    • 2021-09-28
    • 1970-01-01
    相关资源
    最近更新 更多