是否有与posix_memalign相对应的c ++?

时间:2014-12-17 01:09:56

标签: c++

当我调用posix_memalign为我的C ++代码中的Foo类型的对象分配对齐的内存时,我需要reinterpret_cast指向{{1}的指针的地址1}}。

一般来说,当我遇到这种情况时,这意味着我缺少一些语言功能。也就是说,当我打电话给void**时,感觉我在malloc中呼叫c++。 , 对于new中的对齐内存分配,是否存在类型感知new等效项?

3 个答案:

答案 0 :(得分:5)

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

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_cast s。


这是尝试使其通用:

// 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()指针,但您仍然需要执行这些步骤。

答案 1 :(得分:3)

实际上,您不想要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可以针对各个类或全局进行。

答案 2 :(得分:1)

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<sizeof(T), N>,也可以使用C ++ 11。