使用任何缓冲区存储任何数据,使用placement new和memcpy

时间:2013-03-20 23:24:22

标签: c++

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

问题是:我有一个缓冲区,一个数组,使用某种类型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,正如我所说。

2 个答案:

答案 0 :(得分:3)

如果typeTtypeU的大小和对齐要求相同,您可以使用为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没有动态分配,所以无法保证。

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