[英]Allocating an array of aligned struct
我正在尝试分配一个结构数组,我希望每个结构都对齐到64个字节。
我尝试了此操作(目前仅适用于Windows),但不起作用(我尝试使用VS2012和VS2013):
struct __declspec(align(64)) A
{
std::vector<int> v;
A()
{
assert(sizeof(A) == 64);
assert((size_t)this % 64 == 0);
}
void* operator new[] (size_t size)
{
void* ptr = _aligned_malloc(size, 64);
assert((size_t)ptr % 64 == 0);
return ptr;
}
void operator delete[] (void* p)
{
_aligned_free(p);
}
};
int main(int argc, char* argv[])
{
A* arr = new A[200];
return 0;
}
assert ((size_t)this % 64 == 0)
断言((size_t)this % 64 == 0)
模返回16)。 如果该结构仅包含简单类型,则看起来可以工作,但是在包含std
容器(或其他一些std类)时会中断。
难道我做错了什么? 有没有办法做到这一点? (最好与c ++ 03兼容,但是在VS2012中可以使用的任何解决方案都可以)。
编辑:正如肖克瓦夫所暗示的,这有效:
A* arr = (A*)new std::aligned_storage<sizeof(A), 64>::type[200];
// this works too actually:
//A* arr = (A*)_aligned_malloc(sizeof(A) * 200, 64);
for (int i=0; i<200; ++i)
new (&arr[i]) A();
因此,它似乎与new []的使用有关...我很好奇是否有人有解释。
我想知道为什么您需要如此巨大的对齐要求,而且还要在结构中存储动态堆分配的对象 。 但是您可以这样做:
struct __declspec(align(64)) A
{
unsigned char ___padding[64 - sizeof(std::vector<int>)];
std::vector<int> v;
void* operator new[] (size_t size)
{
// Make sure the buffer will fit even in the worst case
unsigned char* ptr = (unsigned char*)malloc(size + 63);
// Find out the next aligned position in the buffer
unsigned char* endptr = (unsigned char*)(((intptr_t)ptr + 63) & ~63ULL);
// Also store the misalignment in the first padding of the structure
unsigned char misalign = (unsigned char)(endptr - ptr);
*endptr = misalign;
return endptr;
}
void operator delete[] (void* p)
{
unsigned char * ptr = (unsigned char*)p;
// It's required to call back with the original pointer, so subtract the misalignment offset
ptr -= *ptr;
free(ptr);
}
};
int main()
{
A * a = new A[2];
printf("%p - %p = %d\n", &a[1], &a[0], int((char*)&a[1] - (char*)&a[0]));
return 0;
}
我没有您的align_malloc和free函数,因此我提供的实现正在执行此操作:
输出:
0x7fff57b1ca40 - 0x7fff57b1ca00 = 64
警告 :如果您的结构中没有填充,则上述方案将破坏数据,因为我会将未对齐偏移量存储在一个内部成员的构造函数将覆盖的位置。 请记住,当您执行“ new X [n]”时,“ n”必须存储在“某处”,因此在调用delete []时,将完成对析构函数的“ n”调用。 通常,它存储在返回的内存缓冲区之前(new可能会分配所需的大小+ 4以存储元素数)。 这里的方案避免了这种情况。
另一个警告 :因为C ++调用此运算符,并在其大小中包含一些额外的填充以存储数组的元素数,所以您可能仍会在对象的返回指针地址中获得“移位”。 您可能需要考虑它。 这就是std :: align的工作,它占用了额外的空间,像我一样计算对齐方式并返回对齐的指针。 但是,你不能同时获得在新的[]过载完成,这是因为()的新回国后这种情况发生了“计数存储”转变。 但是,您可以通过一次分配找出一次“计数存储”空间,并在new []实现中相应地调整偏移量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.