【问题标题】:Aligned heap allocation for unknown types未知类型的对齐堆分配
【发布时间】:2021-04-24 20:36:58
【问题描述】:

鉴于其他未知类型的对齐方式和大小,如何安全地构造正确对齐的空闲存储(堆)?

对于上下文:自动存储版本有据可查。请参阅https://en.cppreference.com/w/cpp/types/aligned_storage 的示例:堆栈上的不透明未初始化存储得到正确对齐,一旦类型已知,以后可以放置新的。

是否可以类似地在堆上进行对齐安全的未初始化分配?一旦类型已知(并在类型感知上下文中通过适当的销毁等删除),此存储稍后将被初始化放置。

以下天真的尝试失败:https://godbolt.org/z/PM1xWoYox

堆存储的心智模型是什么?

【问题讨论】:

  • std::aligned_storage 只是一个类型。是什么阻止您将其分配到堆而不是堆栈上?
  • 好问题:(a) sz 和 align 是运行时值。 (b) 好奇如何正确使用 (sz, align) 运算符 new 和 delete 的重载。例如,即使将 align 参数提供为 __STDCPP_DEFAULT_NEW_ALIGNMENT__,当 new(sz,align) 与类型化删除(不带对齐)配对时,明显的行为也是不正确的。
  • 您是否尝试过分两步删除,因为您也分两步执行了新操作?

标签: c++ memory c++17 memory-alignment


【解决方案1】:

鉴于您在使用newdelete 时遇到的问题,您可以考虑改用aligned_allocfree。例如:

#include <cstdlib>
#include <new>

struct Foo
{
    Foo (double d) : m_d (d) {}
    double m_d;
};

int main ()
{
    void *storage = aligned_alloc (alignof (Foo), sizeof (Foo));
    Foo* foo = new (storage) Foo (3.14);
    ...
    foo->~Foo ();
    free (storage);
}

请注意,要销毁由放置new 创建的对象,您必须显式调用析构函数。你不要打电话给delete。然后你必须释放底层存储。

【讨论】:

  • "要销毁由placement new 创建的对象,您必须显式调用析构函数" 我想这确实是我问题的症结所在,所以,谢谢你这样说。但是,堆存储真的是这样吗?标准中哪里有这样说的?即便如此,delete 不应该调用“~T()”然后释放存储空间吗?什么是 new/delete 的底层模型,即使对齐整数值与两个调用相同(有和没有 std::align_val_t 重载),这种奇偶校验变得有必要强加?
  • 对于其他上下文:我追求比两步删除更干净的解决方案的主要动机是能够从一个未初始化的存储空间中提取一个std::unique_ptr&lt;T&gt; 'ed,并且我不会为此添加自定义删除器(当然,除非它实际上是不可避免的)
  • 您不能调用delete,因为在一般情况下,它不知道如何释放底层存储。将std::unique_ptr 与自定义删除器一起使用肯定会有一些好处。在你的位置上,我会调查的。
  • 实际上,似乎可以将placement new 和delete 配对godbolt.org/z/7bWbPzT6W 至少我找不到产生错误代码的编译器。只有当对齐进入画面时,问题才会显现。
  • 其实不能。例如,placement new 可以与基于堆栈的变量一起用作后备存储。然后尝试拨打delete
猜你喜欢
  • 2011-06-16
  • 2019-02-19
  • 1970-01-01
  • 2014-03-20
  • 2013-08-10
  • 2020-11-02
  • 2021-08-30
相关资源
最近更新 更多