如何使用 new 来过度分配内存以在结构中分配变量?
所以我有几个结构......
struct myBaseStruct
{
};
struct myDerivedStruct : public myBaseStruct
{
int a, b, c, d;
unsigned char* ident;
};
myDerivedStruct* pNewStruct;
我想动态分配足够的空间,以便我可以在某些数据中“memcpy”,包括以零结尾的字符串。基本结构的大小显然是“1”(我假设是因为它不能为零),而派生结构的大小是 20,这似乎是有道理的(5 x 4)。
因此,我有一个大小为 29 的数据缓冲区,前 16 个字节是整数,其余 13 个字节是字符串。
如何为 pNewStruct 分配足够的内存,以便有足够的内存用于字符串?理想情况下,我只想:
- 在 pNewStruct 处分配 29 个字节;
- memcpy 从缓冲区到 pNewStruct;
谢谢,
So I have a couple of structs...
struct myBaseStruct
{
};
struct myDerivedStruct : public myBaseStruct
{
int a, b, c, d;
unsigned char* ident;
};
myDerivedStruct* pNewStruct;
...and I want to dynamically allocate enough space so that I can 'memcpy' in some data, including a zero-terminated string. The size of the base struct is apparently '1' (I assume because it can't be zero) and the size of the derived is 20, which seems to make sense (5 x 4).
So, I have a data buffer which is a size of 29, the first 16 bytes being the ints and the remaining 13 being the string.
How can I allocate enough memory for pNewStruct so that there is enough for the string? Ideally, I just want to go:
- allocate 29 bytes at pNewStruct;
- memcpy from buffer into pNewStruct;
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您回到 C 或放弃这些想法并实际使用 C++。
理想情况下,您应该只说:
myDerivedClass* foo = new myDerivedClass(a, b, c, d, ident);
You go back to C or abandon these ideas and actually use C++ as it's intended.
Ideally you should just say:
myDerivedClass* foo = new myDerivedClass(a, b, c, d, ident);
在当前的 C++ 标准中,
myDerivedStruct
是非 POD,因为它有一个基类。将任何内容memcpy
写入其中的结果是未定义的。我听说 C++0x 将放宽规则,以便比 C++98 中更多的类是 POD,但我还没有研究过。另外,我怀疑很多编译器会以与 POD 不兼容的方式布局您的类。我预计您只会遇到没有进行空基类优化的问题。但它就在那里。
如果是 POD,或者如果您愿意冒险实施,那么您可以使用
malloc(sizeof(myStruct)+13)
或new char[sizeof(myStruct) +13]
分配足够的空间,基本上与 C 中的相同。动机大概是为了避免仅将std::string
成员放入您的类,但代价是必须编写手动内存管理代码。In the current C++ standard,
myDerivedStruct
is non-POD, because it has a base class. The result ofmemcpy
ing anything into it is undefined.I've heard that C++0x will relax the rules, so that more classes are POD than in C++98, but I haven't looked into it. Also, I doubt that very many compilers would lay out your class in a way that's incompatible with PODs. I expect you'd only have trouble with something that didn't do the empty base class optimisation. But there it is.
If it was POD, or if you're willing to take your chances with your implementation, then you could use
malloc(sizeof(myStruct)+13)
ornew char[sizeof(myStruct)+13]
to allocate enough space, basically the same as you would in C. The motivation presumably is to avoid the memory and time overhead of just putting astd::string
member in your class, but at the cost of having to write the code for the manual memory management.您可以对任何类实例进行过度分配,但这意味着一定量的管理开销。执行此操作的唯一有效方法是使用自定义内存分配调用。无需更改类定义,您就可以做到这一点。
假设您没有在层次结构中重载
operator delete
,那么delete pObject
将是销毁pObject并释放已分配内存的正确方法。当然,如果您在多余的内存区域中分配了任何对象,那么您必须在释放内存之前正确释放它们。然后,您可以访问以下地址处的
n
字节原始内存:void* p = pObject + 1
。您可以根据需要memcpy
数据传入或传出该区域。您可以分配给对象本身,而不需要memcpy
其数据。您还可以在类本身中提供一个自定义内存分配器,它需要一个额外的
size_t
来描述要分配的多余内存量,使您能够在单个new
表达式中进行分配,但这需要更多的类设计开销。和
You can overallocate for any class instance, but it implies a certain amount of management overhead. The only valid way to do this is by using a custom memory allocation call. Without changing the class definition, you can do this.
Assuming that you don't overload
operator delete
in the hierarchy thendelete pObject
will be a correct way to destroy pObject and deallocate the allocated memory. Of course, if you allocate any objects in the excess memory area then you must correctly free them before deallocating the memory.You then have access to
n
bytes of raw memory at this address:void* p = pObject + 1
. You canmemcpy
data to and from this area as you like. You can assign to the object itself and shouldn't need tomemcpy
its data.You can also provide a custom memory allocator in the class itself that takes an extra
size_t
describing the amount of excess memory to allocate enabling you to do the allocation in a singlenew
expression, but this requires more overhead in the class design.and
您可以使用 malloc 分配您想要的任何大小:
您有一个不同的问题不过, myDerivedStruct::ident 是一个非常模糊的构造。它是一个指向 char(数组)的指针,那么结构以 char 数组开始的地址结束? ident 可以指向任何地方,并且谁拥有 ident 指向的数组非常不明确。在我看来,您希望该结构以实际的 char 数组本身结束,并且该结构拥有额外的数组。此类结构通常有一个 size 成员来跟踪它们自己的大小,以便 API 函数可以正确管理它们并复制它们,并且按照惯例,额外数据在结构结束后开始。或者它们以 0 长度数组
char ident[0]
结尾,尽管这会给某些编译器带来问题。由于多种原因,此类结构中没有继承的空间:You can allocate any size you want with malloc:
You have a different problem though, in that myDerivedStruct::ident is a very ambigous construct. It is a pointer to a char (array), then the structs ends with the address where the char array starts? ident can point to anywhere and is very ambigous who owns the array ident points to. It seems to me that you expect the struct to end with the actual char array itself and the struct owns the extra array. Such structures usualy have a size member to keep track of teir own size so that API functions can properly manage them and copy them, and the extra data starts, by convention, after the structure ends. Or they end with a 0 length array
char ident[0]
although that creates problems with some compilers. For many reasons, there is no place for inheritance in such structs:在这种情况下,混合
memcpy
和new
似乎是一个糟糕的主意。考虑使用malloc
来代替。Mixing
memcpy
andnew
seems like a terrible idea in this context. Consider usingmalloc
instead.您可以通过执行以下操作动态分配空间:
但是
您确定要这样做吗?
另请注意,如果您打算使用 ident 作为指向字符串开头的指针,那将是不正确的。事实上,您需要 &ident,因为 ident 变量本身位于未使用空间的开头,因此将该空间解释为指针很可能毫无意义。因此,如果 ident 是
unsigned char
或char
而不是unsigned char*
则更有意义。[再次编辑]
我只是想强调一下,你正在做的事情确实是一个非常非常糟糕的主意。
You can dynamically allocate space by doing:
however
Are you sure you want to do this?
Also, note that if you are intending to use ident as the pointer to the start of your string, that would be incorrect. You infact need &ident, since the ident variable is itself at the start of your unused space, interpreting what is at that space as a pointer is most likely going to be meaningless. Hence, it would make more sense if ident were
unsigned char
orchar
rather thanunsigned char*
.[edit again]
I'd just like to emphasise that what you're doing is really a really really bad idea.
类似的事情。
Something like that.
缓冲区大小在编译时已知吗?在这种情况下,静态分配的数组将是一个更简单的解决方案。否则,请参阅上面 Remus Rusanu 的回答。这就是 win32 api 管理可变大小结构的方式。
Is the buffer size known at compile time? A statically allocated array would be an easier solution in that case. Otherwise, see Remus Rusanu's answer above. That's how the win32 api manages variable sized structs.
首先,我不明白拥有
myBaseStruct
基础有什么意义。你没有提供任何解释。其次,您在原始帖子中声明的内容不适用于您描述的数据布局。对于您在OP中描述的内容,您需要结构的最后一个成员是一个数组,而不是一个指针。
数组大小并不重要,但它应该大于0。大小为0的数组在C++中是明确非法的。
第三,如果您出于某种原因想要专门使用
new
,则必须分配所需大小的char
对象的缓冲区,然后将结果指针转换为您的指针输入之后,假设大小正确,您就可以执行
memcpy
了。Firstly, I don't get what's the point of having a
myBaseStruct
base. You proivided no explanation.Secondly, what you declared in your original post will no work with the data layout you described. For what you described in the OP, you need the last member of the struct to be an array, not a pointer
Array size doesn't matter, but it should be greater than 0. Arrays of size 0 are explicitly illegal in C++.
Thirdly, if you for some reason want to use
new
specifically, you'll have to allocate a buffer ofchar
objects of required size and then convert the resultant pointer to your pointer typeAfter that you can do your
memcpy
, assuming that the size is right.