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

发布于 2024-08-15 17:00:30 字数 512 浏览 8 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

花开柳相依 2024-08-22 17:00:30

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

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

理想情况下,您应该只说:

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.

  • Use the constructor to allocate memory and destructor to delete it.
  • Don't let some other code write into your memory space, create a function that will ensure memory is allocated.
  • Use a std:string or std::vector to hold the data rather than rolling your own container class.

Ideally you should just say:

myDerivedClass* foo = new myDerivedClass(a, b, c, d, ident);

小忆控 2024-08-22 17:00:30

在当前的 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 of memcpying 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) or new 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 a std::string member in your class, but at the cost of having to write the code for the manual memory management.

故事未完 2024-08-22 17:00:30

您可以对任何类实例进行过度分配,但这意味着一定量的管理开销。执行此操作的唯一有效方法是使用自定义内存分配调用。无需更改类定义,您就可以做到这一点。

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
};

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.

void* pMem = ::operator new(sizeof(myDerivedStruct) + n);
myDerivedStruct* pObject = new (pMem) myDerivedStruct;

Assuming that you don't overload operator delete in the hierarchy then delete 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 can memcpy data to and from this area as you like. You can assign to the object itself and shouldn't need to memcpy 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 single new expression, but this requires more overhead in the class design.

myDerivedStruct* pObject = new (n) myDerivedStruct;

and

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
};
莫多说 2024-08-22 17:00:30

您可以使用 malloc 分配您想要的任何大小:

myDerivedStruct* pNewStruct = (myDerivedStruct*) malloc(
      sizeof(myDerivedStruct) + sizeof_extra data);

您有一个不同的问题不过, myDerivedStruct::ident 是一个非常模糊的构造。它是一个指向 char(数组)的指针,那么结构以 char 数组开始的地址结束? ident 可以指向任何地方,并且谁拥有 ident 指向的数组非常不明确。在我看来,您希望该结构以实际的 char 数组本身结束,并且该结构拥有额外的数组。此类结构通常有一个 size 成员来跟踪它们自己的大小,以便 API 函数可以正确管理它们并复制它们,并且按照惯例,额外数据在结构结束后开始。或者它们以 0 长度数组 char ident[0] 结尾,尽管这会给某些编译器带来问题。由于多种原因,此类结构中没有继承的空间:

struct myStruct 
{
size_t size;    
int a, b, c, d;    
char ident[0];
};

You can allocate any size you want with malloc:

myDerivedStruct* pNewStruct = (myDerivedStruct*) malloc(
      sizeof(myDerivedStruct) + sizeof_extra data);

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:

struct myStruct 
{
size_t size;    
int a, b, c, d;    
char ident[0];
};
一生独一 2024-08-22 17:00:30

在这种情况下,混合 memcpynew 似乎是一个糟糕的主意。考虑使用malloc来代替。

Mixing memcpy and new seems like a terrible idea in this context. Consider using malloc instead.

绮筵 2024-08-22 17:00:30

您可以通过执行以下操作动态分配空间:

myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(new char[size]);

但是

您确定要这样做吗?

另请注意,如果您打算使用 ident 作为指向字符串开头的指针,那将是不正确的。事实上,您需要 &ident,因为 ident 变量本身位于未使用空间的开头,因此将该空间解释为指针很可能毫无意义。因此,如果 ident 是 unsigned charchar 而不是 unsigned char* 则更有意义。

[再次编辑]
我只是想强调一下,你正在做的事情确实是一个非常非常糟糕的主意。

You can dynamically allocate space by doing:

myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(new char[size]);

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 or char rather than unsigned char*.

[edit again]
I'd just like to emphasise that what you're doing is really a really really bad idea.

帅的被狗咬 2024-08-22 17:00:30
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));

类似的事情。

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));

Something like that.

黎夕旧梦 2024-08-22 17:00:30

缓冲区大小在编译时已知吗?在这种情况下,静态分配的数组将是一个更简单的解决方案。否则,请参阅上面 Remus Rusanu 的回答。这就是 win32 api 管理可变大小结构的方式。

struct myDerivedStruct : public myBaseStruct
{
    int a, b, c, d;
    unsigned char ident[BUFFER_SIZE];
};

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.

struct myDerivedStruct : public myBaseStruct
{
    int a, b, c, d;
    unsigned char ident[BUFFER_SIZE];
};
蝶舞 2024-08-22 17:00:30

首先,我不明白拥有 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 了。

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

struct myDerivedStruct : public myBaseStruct {
    int a, b, c, d;
    unsigned char ident[1];
};

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 of char objects of required size and then convert the resultant pointer to your pointer type

char *raw_buffer = new char[29];
myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(raw_buffer);

After that you can do your memcpy, assuming that the size is right.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文