现在我正在阅读有关对齐,别名,填充和放置新文档的文档,但我仍然不确定如何解决此问题 - 这是我第一次在此级别上遇到内存问题,所以我不自信。
问题是:我有一个缓冲区,一个数组,使用某种类型typeT
,例如
typeT buff[N];
在缓冲区内,我必须在typeU
的开头存储一些buff
类型的其他数据。我们假设K
的{{1}}元素小于或等于typeU
类型的M
元素。
编辑:此问题取决于数据类型,但我的问题是通用的,并保留POD和非POD。但是您可以假设非POD只是POD类型的聚合,没有要复制的动态内存,并且所有数据都包含在结构本身的typeT
字节内。也就是说,不用担心深度/浅度复制。
我最感兴趣的是sizeof(typeX)
和typeT
具有不同路线的情况。哪个对齐尺寸更大是未知的。
问题1 :(最重要的问题)是总是安全地使用新的位置来存储typeU
上的数据,考虑到我会这样做总是使用typeU访问这些数据,如下面的代码?
buff
问题2 :使用typeU *allocData = new (buff) typeU[K];
allocData[0] = foo;
从typeU*
缓冲区复制来自typeT*
的任何数据总是是否安全鉴于我将始终使用memcpy
访问数据,如下面的代码所示?
typeU*
问题3 :(最不重要的问题)是不是总是可以安全地使用这些指针来编译指针并写入数据?喜欢
typeU prevData[K];
memcpy(buff, prevData, sizeof(typeU) * K);
// Is it safe to do the following?
typeU *accessData = reinterpret_cast<typeU *>(buff);
accessData[1] = foo;
即使我总是使用typeU *castData = (typeU*)buff;
castData[2] = something;
使用第一个内存区域(前M个元素)而使用typeU
使用第二个区域(M到N中的元素)?
我希望很清楚我的意思......我搜索了很多,但我仍感到困惑。
此外,请考虑我正在谈论的是C ++ 98或03,而不是11,使用STL的最小子集,没有提升而不是总是在x86上 - 但我可以使用memcpy和placement new,正如我所说。
答案 0 :(得分:3)
如果typeT
和typeU
的大小和对齐要求相同,您可以使用为typeT
分配的未初始化存储来保存typeU
的值。
如果typeT
和/或typeU
具有构造函数或析构函数,则必须确保以正确的顺序正确调用它们。
static_assert(sizeof(typeT) == sizeof(typeU))
static_assert(alignof(typeT) == alignof(typeU))
typeT t[10];
&t[0]->~typeT(); // placement delete t[0] to uninitialize
typeU* p = &t[0];
new (p) typeU(); // construct typeU at t[0]
typeU u& = *p;
u.doStuff();
p->~typeU(); // placement delete typeU at t[0]
new (&t[0]) typeT(); // reconstruct typeT at t[0]
答案 1 :(得分:0)
我刚发现这个article by Sutter引入了一些我不知道的东西
通过new或malloc动态分配的任何内存都是 保证为任何类型的对象正确对齐,但缓冲区 没有动态分配的没有这样的保证
这意味着,首先,我正在做的事情是错误的:
typeT buff[N];
new (buff) typeU[K];
因为buff没有动态分配,所以无法保证。
所以,重点是:要做这种处理,必须动态分配内存。如果不是,答案取决于对齐方式。