posix_memalign 有对应的 c++ 吗?

Posted

技术标签:

【中文标题】posix_memalign 有对应的 c++ 吗?【英文标题】:Is there a c++ counterpart to posix_memalign? 【发布时间】:2014-12-17 01:09:56 【问题描述】:

当我在 C++ 代码中调用 posix_memalignFoo 类型的对象分配对齐内存时,我需要对该指向 void** 的指针的地址执行 reinterpret_cast

一般来说,当我遇到这种情况时,这意味着我缺少一些语言功能。也就是说,当我应该调用new 时,感觉就像我在c++ 中调用malloc。 , c++ 中的对齐内存分配是否存在类型感知 new 等效项?

【问题讨论】:

我认为它会默认对齐(使用 new 时),除非您有目的地确保它不是? @Borgleader,我也这么认为,但事实并非如此。我在运行时检查了地址的最后 6 位上的 assert,但失败了。 使用alignas关键字? Foo重载新的以使用posix_memalign? 您的 GCC 版本可能支持对齐扩展,其工作方式类似于现在标准化的对齐。见gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html 【参考方案1】:

我将首先从核心建议开始。

Foo* aligned_foo() 
  void* raw = 0;
  if(posix_memalign(&raw, 8, sizeof(Foo)))
    return 0; // we could throw or somehow communicate the failure instead
  try
    return new(raw) Foo();
  catch(...)
    free(raw);
    throw;
  

然后当你完成Foo* foo 后,使用foo->~Foo(); free(foo); 而不是delete

请注意缺少reinterpret_casts。


这是一个使其通用的尝试:

// note: stateless.  Deleting a derived with a base without virtual ~base a bad idea:
template<class T>
struct free_then_delete 
  void operator()(T*t)const
    if(!t)return;
    t->~T();
    free(t);
  ;
;
template<class T>
using aligned_ptr=std::unique_ptr<T,free_then_delete<T>>;

// the raw version.  Dangerous, because the `T*` requires special deletion:
template<class T,class...Args>
T* make_aligned_raw_ptr(size_t alignment, Args&&...args) 
  void* raw = 0;
  if(int err = posix_memalign(&raw, alignment, sizeof(T)))
  
    if (err==ENOMEM)
      throw std::bad_alloc;
    return 0; // other possibility is bad alignment: not an exception, just an error
  
  try 
    // returns a T*
    return new(raw) T(std::forward<Args>(args)...);
   catch(...)  // the constructor threw, so clean up the memory:
    free(raw);
    throw;
  

template<class T,class...Args> // ,class... Args optional
aligned_ptr<T> make_aligned_ptr(size_t alignment=8, Args&&...args)
  T* t = make_aligned_raw_ptr<T>(alignment, std::forward<Args>(args)...);
  if (t)
    return aligned_ptr<T>(t);
  else
    return nullptr;

unique_ptr 别名 aligned_ptr 将销毁器与指针捆绑在一起——因为这些数据需要销毁和释放,而不是删除,这很清楚。您仍然可以.release() 指针移出,但您仍然需要执行这些步骤。

【讨论】:

@dyp 失败(非零返回值)我们中止并返回一个仍然为空的retval @dyp 已修复。添加了alignment 参数。我可以让错误代码抛出,但是......我很懒。我想抛出内存是有道理的。 ......那会奏效:aligned_ptr&lt;T&gt; 不能投入建设这一事实也让人感到温暖和模糊。我试图启用 NRVO,所以所有路径都返回 retval。 OP 表明他们正在使用一些古老的编译器,因此“好吧,你不必这样做”,return ; 在 C++03 中不太漂亮。 不确定你在哪里return ;。对于第一个返回 return nullptr; 将起作用,因为该 ctor 不明确。第二个返回不能使用,因为那个ctor 显式的。 @dyp 我修复了另一个错误,并颠倒了建议——把具体的(简短的)版本放在第一位,用你的return new(raw) Foo(); 那个很干净,我几乎想用它作为核心unique_ptr 一个 -- 让unique_ptr 一个只需用删除器包装即可。 @dyp 重写。我认为_raw_ptr_ptr 版本更简洁。现在抛出内存不足,如new【参考方案2】:

实际上,您不想执行reinterpret_cast,因为您的Foo 构造函数不会被调用。如果需要从特殊位置分配内存,则调用placement new 在该内存中构造对象:

void* alloc;
posix_memalign(&alloc, 8, sizeof(Foo));
Foo* foo = new (foo) Foo();

唯一的其他方法(C++11 之前)是为您的类覆盖 new 运算符。如果您有一个总是需要这种特殊分配的特定类,则此方法有效:

class Foo 
    void* operator new(size_t size) 
        void* newobj;
        posix_memalign(&newobj, 8, sizeof(Foo));
        return newobj;
    
;

然后,无论何时您调用new Foo(),它都会调用此分配器。请参阅http://en.cppreference.com/w/cpp/memory/new/operator_new 了解更多信息。可以为单个类或全局覆盖 operator newoperator delete

【讨论】:

如果我不执行reinterpret_cast,我会收到编译器错误(或者可能是升级警告)。 另外我一点也不介意没有调用构造函数(我已经做了一个新的放置),但我非常关心对齐。 对不起,我正在考虑重新解释演员在另一个方向(对 Foo)。确实,Foo** 需要演员表作废**。 我认为这个reinterpret_cast 违反了严格的别名规则。你可以试着通过这样写来避免这种情况:void* foo_v; posix_memalign(&amp;foo_v, 8, sizeof(Foo)); auto foo = new (foo_v) Foo(); 如果你说std::vector&lt;Foo&gt;,你会大吃一惊:-S【参考方案3】:

C++11 增加了对对齐声明和对齐分配的原生语言支持。

您可以在 C++11 中的类型上指定 alignas(N),以指定新对象的最小对齐方式,默认 new 将遵守该对齐方式。

来自cppreference的示例:

struct alignas(16) sse_t  // SSE-safe struct aligned on 16-byte boundaries
    float v[4];
;

那么你可以简单地做

sse_t *ssevec = new sse_t;

要替换posix_memalign,您可以使用std::aligned_storage&lt;sizeof(T), N&gt;,同样在C++11 中。

【讨论】:

AFAIK,alignas 说明符仅适用于变量声明(静态/全局和本地/堆栈变量)。您可以在声明站点将其指定为声明类型的限定符,也可以在我们用于声明的类之一上指定。 这个答案部分错误!在 C++11 中,new 在某些情况下不尊重 alignas(): ***.com/questions/15511909/…

以上是关于posix_memalign 有对应的 c++ 吗?的主要内容,如果未能解决你的问题,请参考以下文章

posix_memalign、malloc 和 calloc 与 lli 解释器有问题

如何使用 posix_memalign 动态分配 64B 对齐的 2D 指针数组

我们啥时候需要使用 posix_memalign 而不是 malloc?

Windows 中 posix_memalign 的正确替代品是啥?

无法在 Visual Studio 2010 中使用函数 posix_memalign

ARM GCC 中对 posix_memalign 的未定义引用