当我调用posix_memalign
为我的C ++代码中的Foo
类型的对象分配对齐的内存时,我需要reinterpret_cast
指向{{1}的指针的地址1}}。
一般来说,当我遇到这种情况时,这意味着我缺少一些语言功能。也就是说,当我打电话给void**
时,感觉我在malloc
中呼叫c++
。
,
对于new
中的对齐内存分配,是否存在类型感知new
等效项?
答案 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 new
和operator 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。