Sign in to follow this  

How to 'insert' a value into a memblock...

This topic is 3862 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Up to this point I havent touched 'memblocks' (I have experience with them, just not in C++), but im trying to implement a message passing system like the one described here (at bottom)... http://www.gamedev.net/reference/articles/article1930.asp ...so I need to allocate a big chunk of memory, which can store a variety of undefined message types. Can anyone explain how I can do something like this...
Quote:
void* ptr = malloc( 256 ); ptr[0] = someFloat; ptr[4] = anotherFloat; //then look them up float* ptrToMyFloat = static_cast<float*>(ptr[0]); float* ptrToMyOtherFloat = static_cast<float*>(ptr[4]);
...and again, I am well aware of the dangers. Like I said, I have experience with this stuff, I am just unaware of the 'proper' syntax for C. Thanks! [Edited by - ZealousEngine on May 17, 2007 7:13:28 PM]

Share this post


Link to post
Share on other sites
instead of:


ptr[0] = someFloat;





do


memcpy( &ptr[0], someFloat, sizeof(float) );






to access...

ptr[0] actually contains your float data. so a pointer to your float data will be &ptr[0]

//just add a & before ptr[0]
float *ptrToMyFloat = static_cast<float*>(&ptr[0]);





-me

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
Ok cool thanks.

So malloc, memcpy, ect.. are the way to do it? There is no 'more proper' c++ way? This looks fine, just want to make sure.


oh. I missed the malloc. instead of malloc it should be:


void *ptr = new void*[256];



then to release the memory

delete[] ptr;



-me

Share this post


Link to post
Share on other sites
Akk nevermind, having some trouble. The following works fine...

Quote:

memcpy( ptr, &someFloat, sizeof(float) );


..but the following generates an error..

Quote:

memcpy( &ptr[0], &someFloat, sizeof(float) );

// error C2036: 'void *' : unknown size


Can you really use [] on a void pointer?

Share this post


Link to post
Share on other sites
hrm... since you're just casting anyway, try making the buffer of type int instead of void* and see if that fixes the problem. I'd thought you should be able to use [] with void*, but maybe I'm just wrong...

-me

Share this post


Link to post
Share on other sites
Well an int is 4 bytes isnt it? Wont that be a problem?

* well I tried...

Quote:

char* ptr = new char[256];
memcpy( ptr[0], &someFloat, sizeof(float) );


..but now im getting..

Quote:

error C2664: 'memcpy' : cannot convert parameter 1 from 'char' to 'void *'

Share this post


Link to post
Share on other sites
It's usual to use char* buffers for this sort of thing, because sizeof(char) == 1, by definition.

Also, '&arr[x]' is equivalent to 'arr + x', which is generally considered neater.

Also, in C++, instead of using memcpy(), use std::copy from <algorithm>:


template <typename T>
void appendToBuffer(char* buffer, int& position, const T& toAppend) {
char* ptrToAppend = reinterpret_cast<char*>(&toAppend);
std::copy(ptrToAppend, ptrToAppend + sizeof(T), buffer + position);
position += sizeof(T);
}

// Sample - append an array of floats to a buffer:
int pos = 0;
char buffer[10 * sizeof(float)];
float f[10];
for (int i = 0; i < 10; ++i) {
appendToBuffer(buffer, pos, f[i]);
// Because 'pos' is passed by reference, it gets implicitly updated each
// time through the loop.
}


Better yet, we could wrap the buffer and position up in a class. Oh, and we could use std::vector<char> for the buffer instead and avoid all that nasty memory management ;) (The 'position' is then implicitly the .size() of the vector, too, so we even save that bit of work.)


class Buffer {
std::vector<char> storage;
public:
// Note how this is designed for chaining, by returning a reference to self.
template <typename T>
Buffer& append(const T& t) {
const int pos = storage.size();
const int size = sizeof(T);
storage.resize(pos + size);
char* ptrToAppend = reinterpret_cast<char*>(&t);
std::copy(ptrToAppend, ptrToAppend + size, storage.begin() + pos);
return *this;
}
};

// somewhere else...
float x, y, z;
Buffer b;
b.append(x).append(y).append(z);

Share this post


Link to post
Share on other sites
Cool.. a neat tidy 'buffer' class. Are you sure it wont hurt performance in anyway? I dont have much experience with 'reinterpret_cast', ect... Also it seems like resizing the vector could be slower than pre allocating a big chunk of memory..

*Ok well I see reinterpret cast is supposed to be the 'least safe', so I assume that also means the 'fastest' as well :p. And I guess I could modify the class to only resize the buffer if the new append wont have enough room (I plan on resetting, and reusing the buffer every frame, so I dont want to be constantly resizing it).

[Edited by - ZealousEngine on May 17, 2007 8:48:24 PM]

Share this post


Link to post
Share on other sites
For next time, this approach can be described more generally as binary serialisation (rather than memblocks). In general it is considered to be reasonably fragile, because you need to manually record the layout of the data you are using (once for reads and once for writes).

Also you should also be aware that Zahlman's code has some gotchas.

Firstly you can't add any type to a buffer, only Plain Old Data (POD) types, that means no structs or classes with pointers, strings, etc.

As it stands you'll also need some way of getting data back out of the buffer at the other end - which means keeping track of some kind of index/iterator/pointer into the container. From experience, it's really easy to make a mistake keeping track of that index.

Share this post


Link to post
Share on other sites
Ok I think I got the hang of this.. so to convert some area of the buffer back into a float, the syntax is...

Quote:

myFloat = *reinterpret_cast<float*>(&buffer[0]);


So I guess with this method, I wont be using void pointers at all? The following 'message system' as described in this article should be exactly the same with char* instead of void* right?

(its at the bottom of the page)
http://www.gamedev.net/reference/articles/article1930.asp

And nobody knows of any better way to do such a message system (with variable type messages) than they way they suggested in that article?

Share this post


Link to post
Share on other sites
When manually allocating memory for basic types, remember the alignment.

While it may work on one processor, it will mysteriously crash on another, if you attempt to use a non-aligned address. I learned this with serialization library.

Which means, for each block you allocate, you should pad it with up to 15 bytes, then make sure the pointer from which you start allocating has address divisible by 16. Could be even more than 16 bytes (not sure right now if 128 bits is largest alignment)

A better way would be to simply have one allocators per type.

Or simply use one of boost pools.

Share this post


Link to post
Share on other sites
Huh? Dont know much about boost pools.. And that sucks about it not working on different machines..

Do you see any other way to implement a sort of 'dynamic argument passing' like they do in the message system in that article?

http://www.gamedev.net/reference/articles/article1930.asp

Share this post


Link to post
Share on other sites
Quote:
Original post by ZealousEngine
Can you really use [] on a void pointer?


Nope you can't. Cannot do arithmetics with void* type. So, instead, should use a char buffer.

Share this post


Link to post
Share on other sites
Hmm I read a little on boost pools, that seems to be for when youre constantly allocating/dealocating memory. Im talking about declaring a big chunk of memory once, and reusing it over and over (like a blackboard). Do I really need to worry about padding things in a case like that? I dont understand why things would work differently on different machines..

And also, why can I not copy a class or struct to this area of memory? Its memory isnt it?

Again, ill admit, I would rather NOT have to do things this way, but I just cant for the life of me see any other (fast) way to pass variable argument types.

Share this post


Link to post
Share on other sites

This topic is 3862 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this