How do I over-allocate memory using new to allocate variables within a struct?

You can allocate any size you want with malloc.

Up vote 1 down vote favorite share g+ share fb share tw.

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, c++ dynamic structure new allocation link|improve this question asked Dec 16 '09 at 22:52acron82.

Alright, thanks for the feedback. I am tempted by the malloc idea, but I am unfamiliar with paradigms which would suggest that this is a bad idea? By all means call me n00b - alternatively, some references to documentation detailing this would be far more productive.

– acron Dec 16 '09 at 23:06 If you want a contiguous variable-length structure, you have to put an array in the end, rather than the pointer. – Alex B Dec 16 '09 at 23:18 Thanks. Yeah, based on Remus answer, this is what I did, and in combination with using malloc, I have got it to work.

To clarify, the reason that the struct is derived is so that I can keep a non-specfic type pointer it and then just memcpy in a loop. The process actually does the following: - Reads a block type byte. - Reads the size of the block.

- Mallocs a member variable of the correct type to the extended size. - Uses a local base class pointer to point to the member variable. - Memcpy's the size into the pointer.

This operates on a loop, based on not knowing what block follows. – acron Dec 16 '09 at 23:34 1 Very important, don't use memcpy unless you can guarantee that the compiler will place the members in the exact same place between the target and destination structures. Compilers are allowed to add padding between members without notifying the User.

The safest and most portable method is to use member-wise copying, either through a copy constructor or a function. – Thomas Matthews Dec 16 '09 at 23:47 If two POD classes have the same data members in the same order, then they're "layout-compatible" (9. 2/14).

Although I can't find the bit of the spec which says so, I'm pretty sure this means exactly that the compiler must place the members in the exact same place, so you can memcpy from one to the other. If it weren't for the base class in this case, then two different classes/structs with the members given in the question, would qualify. The problem is that it's legal for the base class to occupy some bytes.

– Steve Jessop 2/148 at 1:17.

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

1 Array declarations of size 0 are ill-formed in C++ (as well as in C, BTW). All compilers have problems with it, not just some. – AndreyT Dec 16 '09 at 23:23 Yeah, so based on the assumption that each string will have atleast 1 char, I have used 'char ident;'.

This method has worked. – acron Dec 16 '09 at 23:30 1 @AndreyT: GNU C allows that 0-length array, as an extension. Not sure whether that means it "has problems with it".

It forbids it in pedantic mode. C99 allows a flexible-length array at the end of a struct, char ident, which is intended for this purpose. – Steve Jessop Dec 16 '09 at 23:40 1 Old compilers tolerated zero length arrays for the 'struct hack'.

Old system headers were full of structs ending in 0 length arrays. Newer compilers explicitly forbit it, and some accept the new syntax of sizeless array. What 'old' and 'new' means is relative I guess... This is also discussed stackoverflow.com/questions/627364/… – Remus Rusanu Dec 16 '09 at 23:47 1 Since he's using 0 terminates string in his struct he should set the array size to 1.

Then he doesn't need the +1 after the strlen() call. Regardless, this is not a C++ solution at all. – jmucchiello Dec 16 '097 at 14:39.

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

I could do this, but it breaks down efficiency massively. Also, the incoming buffer has the data packed nicely - what is the point in splitting it all up only to reassemble it? All I want to do is copy the data from the buffer and give it some context using my struct.

– acron Dec 16 '09 at 23:16 @acron: Ask yourself if efficiency matters so much that you can't afford to write reliable, readable C++ code. If you determine that it does, consider using C, as suggested. – Steve S Dec 16 '09 at 23:53.

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 charsizeof(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.

Off the top of my head, I don't think this is true. It has no virtual functions or custom default constructor, so I think it is POD. – Autopulated Dec 16 '09 at 23:01 1 Off the top of my head, 9/4: "a POD-struct is an aggregate class", and 8.5.1/1:"An aggregate is an array or class with ... no base classes".

OK, I lied about it being off the top of my head ;-) – Steve Jessop Dec 16 '09 at 23:07 Okay, Spec wins :D – Autopulated Dec 17 '09 at 0:32 @Steve: Then why do compilers (GCC) that complain about certain operations on not-POD classes not complain on simple derived structs? – Zan Lynx Dec 17 '09 at 1:50 @Steve: In particular I can declare arrays of them to overlay mmap()'d data without triggering default constructors. – Zan Lynx Dec 17 '09 at 1:52.

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

I think this is probably the best idea. "D'oh. " – acron Dec 16 '09 at 23:03.

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.

2 Oh God please make the pain stop! – Nikola Smiljani? Dec 16 '09 at 22:59 Why is it a bad idea?

– acron Dec 16 '09 at 23:12 Because: - You'll have to always do all of the memory allocation for these structures yourself, otherwise you'll end up corrupting memory. - The values of the fields of your structure when you memcpy into it will be platform dependant (most obviously they will depend on endianness, and the size of int). - sizeof(myDerivedStruct) will be misleading - Your code will be very confusing to read, and anyone who maintains it in future may not understand what you're doing, even if you do.

– Autopulated Dec 17 '09 at 0:29.

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

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.

I would like to disclaim that doing things this way is a Bad Idea(tm) If you're using c++, you should be using std::string – Bryan Ross Dec 16 '09 at 22:59 STL isn't considered optimal for the platform I'm working, unfortunately :/ – acron Dec 16 '09 at 23:01.

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

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 ident1; }; 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 char29; myDerivedStruct* pNewStruct = reinterpret_cast(raw_buffer); After that you can do your memcpy, assuming that the size is right.

You go back to C or abandon these ideas and actually use C++ as it's intended.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions