【问题标题】:Is it safe to combine sizeof and placement new?将 sizeof 和 Placement new 结合起来是否安全?
【发布时间】:2012-10-15 20:39:01
【问题描述】:

考虑以下类:

template <class T>
class defer {
public:
    template <class ...Args>
    void construct(Args&&...);
    T& obj();
    ~defer();
private:
    std::uint8_t memory[sizeof(T)];
    T * ptr();
};

template <class T>
template <class ...Args>
void defer<T>::construct(Args&& ...args) {
    new(static_cast<void*>(&memory[0])) T(std::forward<Args>(args)...);
}

template <class T>
T& defer<T>::obj() {
    return *(ptr());
}

template <class T>
defer<T>::~defer() {
    ptr()->~T();
}

template <class T>
T * defer<T>::ptr() {
    return static_cast<T*>(&memory[0]);
}

现在我知道这有问题,但为了使代码简短便于讨论,我们将假设 defer::construct() 总是在对象超出范围之前被调用。

话虽如此,这样做是否总是安全的?或者在具有其他疯狂的多重虚拟继承的一些奇怪的极端情况下,std::uint8_t[sizeof(T)] 可以不分配足够的空间吗?

【问题讨论】:

  • std::uint8_t[sizeof(T)] 将始终有足够的空间。但是......它可能并不总是有正确的对齐方式(std::aligned_storage 可以提供帮助)。
  • uint8_t可选。使用uint_least8_tuint_fast8_t;它们将永远存在。
  • @Pete Becker:是的,但你知道有哪些平台没有 8 位整数类型吗?此外,我知道在某些平台上 uint_least8_t 和 uint_fast8_t 都是为了提高效率而对 int 的 typedef,这可能意味着 300% 的内存开销。 std::uint8_least8_t[sizeof(T)/sizeof(std::uint_least8_t)+((sizeof(T) % sizeof(std::uint_least8_t) != 0) ? 1 : 0)] 有效,但对我来说有点难看...
  • uint_least8_t 必须是具有至少 8 位的无符号类型的同义词,“这样尺寸较小的无符号类型至少具有指定的宽度”。 (C 标准,7.20.1.2/2)。如果你的实现将它定义为int,当有更小的类型可用时,它不仅有错误的属性(因为它是有符号类型),而且它太大了,因此不符合标准。

标签: c++ templates c++11 placement-new


【解决方案1】:

R。 Martinho Fernandes 击败了我!使用

typename std::aligned_storage<sizeof(T)>::type  memory;

你可以走了。详情请见here


正如我们的评论员小组所指出的,默认对齐总是足够的,但可能比您的类型所需的更严格(因此您使用额外的填充浪费空间)。您可以通过明确指定它来避免这种情况:

typename std::aligned_storage<sizeof(T), alignof(T)>::type memory;

【讨论】:

  • 哈哈,有那么一瞬间你犯了忘记::type的常见错误:P
  • aligned_storage&lt;sizeof(T),alignof(T)&gt; 呢?没什么大不了的,但在 T 不需要默认(最大)对齐的情况下可能会节省填充。
  • 默认对齐方式是“对任何大小不大于要求的长度的 C++ 对象类型的最严格的对齐要求”。类似于分配char 数组时的对齐要求。在某些情况下,您不需要如此严格的对齐;例如如果 T 是 int[2],那么您只需要为 int 对齐,但对于任何两倍大小的对象,默认对齐就足够了。
  • 干杯 - 修复了对齐描述。
  • aligned_storage 可能已经在内部使用它,所以不清楚你有什么收获,但它应该可以工作。
猜你喜欢
  • 2011-10-02
  • 2014-06-15
  • 2012-07-16
  • 2020-02-24
  • 2017-09-16
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
相关资源
最近更新 更多