Jump to content
  • Advertisement
Sign in to follow this  

Dynamic Data Member Allocation

This topic is 3433 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

Hello everybody. I have a question regarding pointer data members in a class. Say I have a class like this.

class Any 
{
	public:
		int *num1;
		int *num2;
};


Now what I would like to do is allocate 8 bytes of memory for this class so that num1 can fit into the first 4 bytes and num2 can fit into the last 4 bytes. You will begin to see the problem with this when I post the following code (or so I believe there to be):
class Any 
{
	public:
		Any(void);
		int *num1;
		int *num2;
};

Any::Any(void)
{
	num1 = new int;
	num2 = new int;
}

int main(void)
{
	Any *myClass = new Any;
}


Now what I believe happens here is that 8 'random' bytes get allocated to the any object and then 8 bytes get allocated to both integers in the constructor. This is a total of 16 bytes when the class clearly requires only 8. That's double the memory! I did a test with simply doing this:
#include <iostream>
using namespace std;

class Any 
{
	public:
		Any(void);
		int num1;
		int num2;
};

Any::Any(void)
{
	num1 = 0;
	num2 = 0;
}

int main(void)
{
	Any *myClass = new Any;
	int *pointer1 = &myClass->num1;	
	int *pointer2 = &myClass->num2;

	cout << myClass << "\n";
	cout << pointer1 << "\n";
	cout << pointer2 << "\n";
}


Now the output to this is exactly what I thought. num1 and the myClass pointer have the same exact address and num2 has an address that is exactly 4 bytes after num1 and myClass. Now my question is: Is there a way to do this by dynamically allocating using the first code sample so that it uses 8 bytes, instead of 16 (so I think), like the second sample? This is simply me being curious, that and I would assume that a lot of classes that poeple build have some pointer variables. I was wondering how people dealt with dynamic allocation this way. The only way I see to do this is somehow use placement new and send or give the constructor the address of the allocated memory for the Any* pointer (8 Bytes) and have placement new allocate the memory to num1 and num2 using this memory block. Thanks - Lo$t

Share this post


Link to post
Share on other sites
Advertisement
Quote:

Now what I would like to do is allocate 8 bytes of memory for this class so that num1 can fit into the first 4 bytes and num2 can fit into the last 4 bytes.


I'm kind of having difficulty understanding what you want. The size of a class is determined by its variables. Each int is 4 bytes, so the class should be 8 bytes. I guess you would have to find out where classes are stored in memory and where variables are stored. I don't have a full understanding of it, but Pointer variables are stored on the HEAP I believe and local variables are stored on the STACK. I just faintly remember so I hope that helps get you started.

Share this post


Link to post
Share on other sites
Ok let me see if I can explain this a little bit better. If you take a look at the second code sample, you will see this line: Any *myClass = new Any; Now, given the nature of the new, this will allocate 8 bytes of memory (since there are 2 integers, 4 bytes each). Say this has address 00004000; Now if you take a look at the constructor which is also being called, this allocates 2 new integer objects. Each one gets allocated 4 bytes. Say num1 has address 00004010 and num2 has address 00004100. Altogether that is 16 bytes when the class only needs 8 bytes. What I am surmising is when one has pointer variables and allocates memory this way, more memory is used than is needed for the single class AND the addresses that get sent back from new do not technically have to be aligned to each other. For example, instead of getting memory back like this: 00004000, 00004004 and 00004008, we could get addresses that are all over the place such as: 00005000, 00004000, and 12000000. What I believe is that new has no guarantee that it will return adjacent memory. The real question is, is my understanding correct and is there a way to do it so that the allocation uses only 8 bytes instead of 16, or is it wrong and does it only use 8 bytes?

Share this post


Link to post
Share on other sites
I'm not 100 percent correct here, so don't take my info as "correct"

Quote:
Now what I believe happens here is that 8 'random' bytes get allocated to the any object and then 8 bytes get allocated to both integers in the constructor. This is a total of 16 bytes when the class clearly requires only 8. That's double the memory!



edit:
bleh.. maybe you are actually.. I guess it's the price you have to pay for using a pointer for only 1 int.

If you did.

num_1 = new int[x];

you could potentially save 4 bytes =p.

[Edited by - Arianit on December 25, 2008 2:46:32 AM]

Share this post


Link to post
Share on other sites
Let me show with example code. Here is the first iteration of the sample program


#include <cstdlib>
#include <iostream>
#include <new>
#include <windows.h>
using namespace std;

class Any
{
public:
int *num1;
float *num2;
Any(void);
};

Any::Any(void)
{

}

int main(void)
{
Any *myClass = new Any; // This allocates memory dynamically
cout << sizeof(*myClass) << "\n"; // This prints out 8 to the screen (8 bytes)
cout << myClass << "\n"; // This prints out the address 00345C00
//*myClass->num1 = 2; // This causes a crash because memory has not been allocated to num1 yet
}



Now here is the second iteration of the program with me allocating memory to each member variable


#include <cstdlib>
#include <iostream>
#include <new>
#include <windows.h>
using namespace std;

class Any
{
public:
int *num1;
float *num2;
Any(void);
};

Any::Any(void)
{
num1 = new int;
num2 = new float;
}

int main(void)
{
Any *myClass = new Any; // This allocates memory dynamically
cout << sizeof(*myClass) << "\n"; // This prints out 8 to the screen (8 bytes)
cout << myClass << "\n"; // This prints out the address 00345C00
*myClass->num1 = 2; // This does no cause a crash
cout << myClass->num1 << "\n"; // This prints out a totally random address allocated by the first new
// in the constructor - 00345C38 - That is a 38 byte (hex) mis allignment
cout << sizeof(*myClass->num1)
<< "\n"; // This prints out 4 to the screen (4 bytes)
cout << myClass->num2 << "\n"; // This prints out 000345C68 - 28 byte (hex) mis allignment
cout << sizeof(*myClass->num2)
<< "\n"; // This also prints out 4 to the screen (4 bytes)
}



As I have show in the code and have read on my own screen, instead of 8 bytes being allocated contiguously like I want, I am getting 3 completely different pointer addresses with completely different mis alignments. Also when I take the size of each de referenced pointer (to get the size of the actual object at that location) I am getting 8 bytes for the class object, and 4 bytes for each member. It is in fact allocating 16 bytes of memory. I want 8 bytes.

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77
Let me show with example code. Here is the first iteration of the sample program

*** Source Snippet Removed ***

Now here is the second iteration of the program with me allocating memory to each member variable

*** Source Snippet Removed ***

As I have show in the code and have read on my own screen, instead of 8 bytes being allocated contiguously like I want, I am getting 3 completely different pointer addresses with completely different mis alignments. Also when I take the size of each de referenced pointer (to get the size of the actual object at that location) I am getting 8 bytes for the class object, and 4 bytes for each member. It is in fact allocating 16 bytes of memory. I want 8 bytes.


Yes, that is correct it would seem. It seems like you have to pay the price if you're allocating in such a bizarre way . I'm not sure of a way to completely reduce the overhead but my above post can reduce it by a fraction if you have the same variables as the original source. I'll post here if I find anything =p

Share this post


Link to post
Share on other sites
Quote:
Now what I would like to do is allocate 8 bytes of memory for this class so that num1 can fit into the first 4 bytes and num2 can fit into the last 4 bytes.


You've already solved your own problem:


class Any
{
public:
Any(void);
int num1;
int num2;
};



When you allocate an instance of Any, either via the new operator or on the stack, 8 bytes are allocated (sizeof(Any) is 8). The first 4 bytes correspond to num1, and the second 4 bytes correspond to num2.


class Any
{
public:
Any(void);
int *num1;
int *num2;
};

Any::Any(void)
{
num1 = new int;
num2 = new int;
}



With this version, you're performing a total of 3 allocations: one allocates 8 bytes for the Any instance (4 bytes for the num1 pointer, 4 bytes for the num2 pointer). Now of course, if you want to actually store valid data, num1 and num2 have to point to valid memory. Hence your 2 additional allocations in the constructor of Any: both allocate 4 bytes each, for a total of 8 more bytes.

You can't expect to perform additional allocations and not use more memory. If you just want to store ints, there is no good reason to declare the members as pointers and do more allocations, because you can just use a plain old int for less code and less memory.

Share this post


Link to post
Share on other sites
I assume your code is a simplified example, and you really want to initialize a member variable of a user-defined type which doesn't have a default constructor? In that case, you don't need pointers, just use initialization lists:

class Foo
{
Bar x;
public:
Foo(Bar x): x(x) {}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77

Is there a way to do this by dynamically allocating using the first code sample so that it uses 8 bytes, instead of 16 (so I think), like the second sample?


It's something like this:
template < class T, bool >
struct Type {
T * operator->() {
return &value;
}
T * operator*() {
return &value;
}

T value;
};

template < class T >
struct Type<T, false> {
T * operator->() {
return value;
}
T * operator*() {
return value;
}
T * value;
}

template < class T >
struct Wrapper {
Type<T, (sizeof(T) <= sizeof(void*) > value;
};

struct Foo {
Wrapper<int> a; // stored inside Foo
Wrapper<double> b; // dynamically allocated
Wrapper<std::string> c; // same
};


What happens here is that if size of type is smaller or equal to that pointer, then it will be allocated in-place. Otherwise, it's allocated on heap.

This approach however requires value semantics to be implemented for Type, so dynamic allocations are performed automatically.

The reason for this lies in entropy. If small types (x<=sizeof(void*)) were pointers, there would need to exist NULL value for them. Since indication of such state requires at least 1 bit of information, the case of (x == sizeof(void*)) would require one extra bit, requiring heap allocation. And since 32-bit types are fairly common, it would defeat the most common case.

Share this post


Link to post
Share on other sites
As others above me have already said, you just don't want to use dynamic allocation in this case. When you store your int and float in the class directly, you're already allocating memory for them when you create an instance of that class. There's no need to dynamically allocate those members.


Just a note on dynamic allocation: you consistently forget to release the memory you allocated in your examples. I hope that's because they're examples, but in real code, you should delete what you new once you don't need it anymore. And since that's easy to forget, people have invented so-called smart pointers, that can do it automatically for you.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!