如何使用new在结构中分配变量来过度分配内存?

时间:2009-12-16 22:52:13

标签: c++ dynamic structure new-operator allocation

所以我有几个结构......

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;

谢谢,

9 个答案:

答案 0 :(得分:6)

你回到C或放弃这些想法,并实际使用C ++。

  • 使用构造函数分配内存和析构函数以将其删除。
  • 不要让其他代码写入您的内存空间,创建一个确保分配内存的函数。
  • 使用std:string或std :: vector来保存数据,而不是滚动自己的容器类。

理想情况下,你应该说:

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 charchar而不是unsigned char*,那将更有意义。

[再次编辑] 我只想强调一下,你所做的真的是一个非常糟糕的主意。

答案 4 :(得分:1)

在这种背景下,混合memcpynew似乎是一个糟糕的主意。请考虑改为使用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,假设尺寸合适。