【问题标题】:How to safely construct a C++ object in malloc'ed memory with a header object如何使用标头对象在 malloc 内存中安全地构造 C++ 对象
【发布时间】:2017-03-17 12:30:22
【问题描述】:

我想在另一个分配器(通常在内部调用 realloc)返回的内存中构造任意 C++ 对象。我知道在 malloc 的内存中做一个新的放置通常是可以的。但是,我希望所有 C++ 对象在连续分配的内存中都有另一个公共对象。此标头对象将包含有关以下 C++ 对象的信息。从对齐的角度来看,我不知道分配 (sizeof(header) + sizeof(type)) 内存然后在 (mem + sizeof(header)) 处构造类型是否安全。我认为这不是因为 (mem + sizeof(header)) 不能保证正确对齐类型。

我考虑了一些可能性,例如生成一个模板类型,该模板类型声明标头,后跟类型 T 并分配 sizeof(ObjPlusHeader<T>)。但是,问题是该结构将作为 void* 出现在我的代码的另一部分中(由我无法控制的外部库强制执行),因此我必须知道将其转换为什么。我想转换为 Header* 而不是ObjectPlusHeader<???>*

我知道使用标准布局类型,我可以将对象转换为指向其第一个成员的指针。但是,T 不一定是标准布局,在这种情况下,ObjectPlusHeader<T> 也不会是标准布局,即使 Header 是。我还考虑过让包装器模板从 Header 公开派生,从 T 私下派生而不是包含 T。但是,将 void* 直接转换为 Header* 而不首先转换为存储的实际类型仍然是不合法的我不会知道的。

我想要的是由分配器(基本上是 realloc)分配的连续内存,我知道 Header 位于开头,并且任意 C++ 对象跟随在我知道并可以存储的某个正确对齐的地址 >= mem + sizeof(Header)在标题中。所以给定 void* 我可以将它转换为 Header* 并获取对象。但是,我不确定潜在的对齐问题。

【问题讨论】:

  • 如果对象应该捆绑在一起,请将它们存储为std::pair
  • @NathanOliver。确实,但是当 T 不一定是标准布局时,将 std::pair
    * 转换为 Header* 是否安全?你看,问题的第二部分是我不知道这对的实际类型。我需要保证我可以转换为 Header* 并从那里开始。
  • 你为什么不通过alignof获得所需的对齐并相应地调整指针?即自己添加正确的填充量。
  • @authentec 子类化怎么样?绝对允许向/从 Header 的(模板)子类进行转换。
  • @o11c 是的,但不幸的是我不控制存储的指针值。分配库允许我请求任意大小的内存块,它给了我一个指向它的指针,我可以在其中写入我想要的内容(使用子类化方法,这将是最派生的对象) T 子对象)。在某些时候,它可能会将指向它分配为 void* 的内存的指针交还给我。我别无选择,只能将它投射到我写进记忆的任何东西上。那是Derived<T>*,但那时我不知道 T。

标签: c++ memory


【解决方案1】:

只需编写一个 (constexpr) 函数来计算适当的填充:

template<typename T>
size_t paddingAfterHeader() {
   auto rem = sizeof(Header)%alignof(T);
   return rem ? alignof(T) - rem : 0; 
}

分配:

void *mem = malloc( sizeof( Header ) + paddingAfterHeader<T>() + sizeof(T) );

【讨论】:

  • 感谢斯拉瓦的建议。分配会是什么样子? malloc(sizeof(std::pair
    ))?编辑:我明白了,我应该做 malloc(sizeof(Header) + offsetAfterHeader() + sizeof(t))
  • @authentec 好问题,实际上计算填充会更有用,已修复。
  • *就我个人而言,我会写template &lt;typename T&gt; size_t SizeofHeaderRoundedUp() { return (sizeof(Header)+alignof(T)-1))/alignof(T)*alignof(T); } - 可能会有更多行。
【解决方案2】:

如果以最大对齐方式声明标头,则不必担心以下对象需要额外对齐。

#include <cstddef>

struct
alignas(std::max_align_t)
Header
{
    char body[17];
};

#include <iostream>

int main()
{
    std::cout << "size: " << sizeof(Header) << std::endl;
    std::cout << "align: " << alignof(Header) << std::endl;
}

在我的系统上,输出是:

size: 32
align: 16

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2019-09-12
    • 2015-02-27
    • 2010-10-25
    相关资源
    最近更新 更多