所以我有几个结构......
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分配足够的内存,以便字符串足够?理想情况下,我只想去:
谢谢,
答案 0 :(得分:6)
你回到C或放弃这些想法,并实际使用C ++。
理想情况下,你应该说:
myDerivedClass * foo = new myDerivedClass(a,b,c,d,ident);
答案 1 :(得分:4)
在当前的C ++标准中,myDerivedStruct
是非POD,因为它有一个基类。 memcpy
任何内容的结果都是未定义的。
我听说C ++ 0x会放松规则,所以POD比P ++ 98更多,但我还没有调查过。此外,我怀疑很多编译器会以与POD不兼容的方式布置您的课程。我希望你只会遇到没有进行空基类优化的问题。但它就是。
如果是POD,或者您愿意利用实施机会,那么您可以使用malloc(sizeof(myStruct)+13)
或new char[sizeof(myStruct)+13]
分配足够的空间,基本上与您在C中的空间相同这个动机可能是为了避免在你的班级中放一个std::string
成员的内存和时间开销,但代价是必须为手动内存管理编写代码。
答案 2 :(得分:3)
您可以为任何类实例进行全面分配,但这意味着需要一定的管理开销。唯一有效的方法是使用自定义内存分配调用。不改变类定义,你可以这样做。
void* pMem = ::operator new(sizeof(myDerivedStruct) + n);
myDerivedStruct* pObject = new (pMem) myDerivedStruct;
假设您没有在层次结构中重载operator delete
,那么delete pObject
将是销毁pObject和释放已分配内存的正确方法。当然,如果在超出内存区域中分配任何对象,则必须在释放内存之前正确释放它们。
然后,您可以在此地址访问n
字节的原始内存:void* p = pObject + 1
。您可以根据需要memcpy
数据进出该区域。您可以分配给对象本身,而不需要memcpy
其数据。
您还可以在类本身中提供一个自定义内存分配器,它需要额外的size_t
来描述要分配的超额内存量,使您能够在单个new
表达式中进行分配,但是这样在课堂设计中需要更多的开销。
myDerivedStruct* pObject = new (n) myDerivedStruct;
和
struct myDerivedStruct
{
// ...
void* operator new(std::size_t objsize, std::size_t excess storage);
// other operator new and delete overrides to make sure that you have no memory leaks
};
答案 3 :(得分:1)
您可以通过执行以下操作动态分配空间:
myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(new char[size]);
然而
你确定要这样做吗?
另外,请注意,如果您打算使用ident作为指向字符串开头的指针,那将是不正确的。你实际上需要&amp; ident,因为ident变量本身就是你未使用的空间的开头,解释在那个空间作为指针很可能毫无意义。因此,如果ident是unsigned char
或char
而不是unsigned char*
,那将更有意义。
[再次编辑] 我只想强调一下,你所做的真的是一个非常糟糕的主意。
答案 4 :(得分:1)
在这种背景下,混合memcpy
和new
似乎是一个糟糕的主意。请考虑改为使用malloc
。
答案 5 :(得分:1)
您可以使用malloc分配所需的任何尺寸:
myDerivedStruct* pNewStruct = (myDerivedStruct*) malloc(
sizeof(myDerivedStruct) + sizeof_extra data);
你有一个不同的问题,因为myDerivedStruct :: ident是一个非常恶劣的构造。它是一个指向char(数组)的指针,然后结构以地址结束,其中char数组开始了吗? ident可以指向任何地方,并且拥有阵列标识的非常暧昧。在我看来,您希望结构以实际的char数组本身结束,并且struct拥有额外的数组。这样的结构通常有一个size成员来跟踪teir自己的大小,以便API函数可以正确地管理它们并复制它们,并且按照惯例,在结构结束后,额外的数据开始。或者它们以0长度数组char ident[0]
结束,尽管这会给某些编译器带来问题。由于许多原因,在这种结构中没有继承的地方:
struct myStruct
{
size_t size;
int a, b, c, d;
char ident[0];
};
答案 6 :(得分:0)
char* buffer = [some data here];
myDerivedStruct* pNewStruct = new myDerivedStruct();
memcpy(buffer,pNewStruct,4*sizeof(int));
pNewStruct->ident = new char[ strlen(buffer+(4*sizeof int)) ];
strcpy(pNewStruct->ident,buffer+(4*sizeof int));
类似的东西。
答案 7 :(得分:0)
编译时是否知道缓冲区大小?在这种情况下,静态分配的数组将是更容易的解决方案。否则,请参阅上面的Remus Rusanu的回答。这就是win32 api如何管理可变大小的结构。
struct myDerivedStruct : public myBaseStruct
{
int a, b, c, d;
unsigned char ident[BUFFER_SIZE];
};
答案 8 :(得分:0)
首先,我不明白拥有myBaseStruct
基础是什么意思。你没有解释任何解释。
其次,您在原始帖子中声明的内容将无法使用您描述的数据布局。对于您在OP中描述的内容,您需要结构的最后一个成员是数组,而不是指针
struct myDerivedStruct : public myBaseStruct {
int a, b, c, d;
unsigned char ident[1];
};
数组大小无关紧要,但应该大于0.数组0的数组在C ++中显然是非法的。
第三,如果由于某种原因想要专门使用new
,则必须分配一个所需大小的char
个对象的缓冲区,然后将结果指针转换为指针类型
char *raw_buffer = new char[29];
myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(raw_buffer);
之后,您可以执行memcpy
,假设尺寸合适。