使用placement-new,复制存储然后访问值undefined行为?

时间:2018-04-15 11:46:55

标签: c++ language-lawyer undefined-behavior placement-new

S为结构类型,其中包含具有最大对齐和固定大小的字符数组data。我们的想法是S能够存储任何类型T的对象,其大小不超过限制,并且可以简单地复制构造并且可以轻易破坏。

static constexpr std::size_t MaxSize = 16;
struct S {
    alignas(alignof(std::max_align_t)) char data[MaxSize];
};

Placement-new用于将T类型的对象构造到新S对象的字符数组中。然后,该对象被复制任意次,包括返回并按值传递。

template <typename T>
S wrap(T t) {
    static_assert(sizeof(T) <= MaxSize, "");
    static_assert(std::is_trivially_copy_constructible_v<T>, "");
    static_assert(std::is_trivially_destructible_v<T>, "");

    S s;
    new(reinterpret_cast<T *>(s.data)) T(t);
    return s;
}

稍后给出此S值的副本,reinterpret_cast用于从指向字符数组开头的指针获取T*,然后T对象以某种方式访问​​。 T类型与创建值时的类型相同。

void access(S s) {
    T *t = reinterpret_cast<T *>(s.data);
    t->print();
}

我想知道这个方案中是否有任何未定义的行为以及它将如何解决。例如,我担心:

  • &#34;重用对象存储&#34;是否存在问题,即std::launder旨在解决的问题?在构造data的实例后,我不确定将T作为字符数组访问是否有效。我是否需要在访问值的位置std::launder,以及为什么?
  • 生成的S复制构造函数是否存在复制data中所有字节的问题,因为某些字节可能尚未初始化?我担心sizeof(T)以外的字节以及T对象中可能未初始化的字节(例如填充)。

我的用例是实现一个非常轻量级的多态函数包装器,它能够与满足我为T列出的那些要求的任何可调用函数一起使用。

1 个答案:

答案 0 :(得分:0)

THE TERM has a long definition that may run
  on for quite some time.
这可能是有用的。它将编译器对数据的解释从一种pod类型转换为另一种pod类型,并在优化下编译为noop。

所以把你的缓冲区,洗衣荚拿到T,写到它,洗衣荚回到gdneric存储。阅读,洗衣舱到T.请注意,所有通过T指针写入后应将其清洗回通用存储,以避免使用别名规则来优化掉看似丢弃的ptr上的写入。