2

有一段时间了,我正在阅读有关对齐、别名、填充和放置新的文档,但我仍然不确定如何解决这个问题——这是我第一次在这个级别上遇到内存问题,所以我我不自信。

问题是:我有一个缓冲区,一个数据数组,它使用某种类型typeT,例如

typeT buff[N];

在该缓冲区内,我必须typeUbuff. 让我们假设有 的K元素typeU,它小于或等于M类型的元素typeT

编辑:这个问题取决于数据类型,但我的问题是通用的,适用于 POD 和非 POD。但是您可以假设非 POD 只是 POD 类型的聚合,没有要复制的动态内存,并且所有数据都包含在sizeof(typeX)结构本身的字节中。也就是说,不用担心深/浅复制

我最感兴趣的情况typeTtypeU不同的对齐方式。哪个对齐大小更大尚不清楚。

问题 1:(最重要的问题)考虑到我将始终使用 typeU 访问这些数据,就像在下面的代码中一样,使用新位置存储我的数据是否总是安全的?buff

typeU *allocData = new (buff) typeU[K];
allocData[0] = foo;

问题 2 :从using类型的缓冲区中复制任何数据是否总是安全的,因为我将始终使用 访问数据,就像在下面的代码中一样?typeU*typeT*memcpytypeU*

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;

问题 3:(最不重要的问题)只是转换指针并使用它们写入数据并不总是安全的吗?像

typeU *castData = (typeU*)buff;
castData[2] = something;

即使我总是使用内存的第一个区域(前 M 个元素)使用typeU和第二个区域(从 M 到 N 的元素)使用typeT

我希望我的意思很清楚......我搜索了很多,但我仍然很困惑。

另外,请考虑我说的是 C++98 或 03,而不是 11,它具有 STL 的最小子集,没有提升,并不总是在 x86 上 - 但我可以使用 memcpy 和 Placement new,正如我所说。

4

2 回答 2

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]
于 2013-03-20T23:50:46.210 回答
0

我刚刚发现了 Sutter 的这篇文章,其中介绍了一些我不知道的东西

通过 new 或 malloc 动态分配的任何内存都可以保证为任何类型的对象正确对齐,但未动态分配的缓冲区没有这样的保证

这意味着,首先,像我一样做是错误的:

typeT buff[N];
new (buff) typeU[K];

因为buff不是动态分配的,所以不能保证。

所以,关键是:要进行这种处理,必须动态分配内存。如果不是,答案取决于对齐方式。

于 2013-03-21T10:49:50.843 回答