• Advertisement
Sign in to follow this  

Dynamic Data Member Allocation

This topic is 3341 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
Yeah its because they are examples. That is why I am not releasing memory. Secondly perhaps my example was over simplified. I was using a float and an integer to be simple. However for instance, what if I had a pointer member that was a char pointer for something such as a string? Then I would be allocating a lot more memory then needed. What if the string was 20 or more characters long? My example would make a lot more sense then. Also stuff like having pointers to other classes or structs interests me in the Any class. This is really what I wanted the pointers for: dynamically allocating other classes and or strings (char pointers). How would one deal with this?


Thanks for the responses everybody. Note I am still studying what you said, Antheus. =p

Lo$t

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77
what if I had a pointer member that was a char pointer for something such as a string?

char pointer for strings? We aren't writing in C anymore. Use std::string.

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77
However for instance, what if I had a pointer member that was a char pointer for something such as a string? Then I would be allocating a lot more memory then needed.


Not sure what you mean. You'll have a dynamically allocated string (say 20 bytes), plus a pointer to it somewhere in a class for a total of 24 bytes (on a 32 bit machine). That sounds pretty reasonable. Exactly how much do you "need," and how much would you allocate? If you don't want to waste memory, only allocate the amount of space you need.

Quote:
This is really what I wanted the pointers for: dynamically allocating other classes and or strings (char pointers). How would one deal with this?


You've done this already in your example using the int pointers. Replace int* with a pointer to whatever object/string you want to point to, and then allocate and create the appropriate objects with the new operator. Memory usage is the size of the dynamically allocated object, plus the size of a pointer to hold the address. If you don't store the address in a pointer (and later free it), you've got a memory leak.

Maybe your question is really this: "I have an Any class that I want to use as a variant that can hold a variety of types and values, but only one at a time. How do I write the class so that I only allocate memory for each type up front when I only plan on using one at a time?" If so, then something like this:


#include <string>
#include <cassert>

class Any
{
public:
enum Type {INT, FLOAT, STRING};

explicit Any (int i) {type_ = INT; int_ = i;}
explicit Any (float f) {type_ = FLOAT; float_ = f;}
explicit Any (const std::string &s)
{
type_ = STRING;
string_ = new std::string(s);
}

~Any ()
{
if (type_ == STRING && string_)
{
delete string_;
}
}

int GetInt () const {assert(type_ == INT); return int_;}
float GetFloat () const {assert(type_ == FLOAT); return float_;}
const std::string *GetString () const
{
assert(type_ == STRING);
return string_;
}

private:
Type type_;
union
{
int int_;
float float_;
std::string *string_;
};
};



Use a union to pack values/pointers into the same space. You then need another member to determine which field in the union is valid at any given time. Here, you only allocate memory when needed (for a string) and store ints and floats directly in the Any instance.

Share this post


Link to post
Share on other sites
Ok.. I think that some of you are mis interpreting what I am trying to prove / say here. Again I will try to explain with code.




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

class Any
{
public:
char *myString;
Any(void);
};

Any::Any(void)
{
myString = new char[40]; // This allocates space for 40 bytes
}

int main(void)
{
Any *myClass = new Any; // This ALSO allocates space for 40 bytes
// What I want to do is only allocate space for 40 bytes in total
// and have the myString variable's 40 bytes be allocated from the
// myClass pointer's already allocated memory , ELSE we are using
// 80 bytes for allocation instead of 40.
}





For simplicity I am not deleting or freeing the memory and I am also not using std::string. I am not exactly sure how else to explain this because how I am thinking of it in my mind is crystal clear. When we do allocation this way, as shown in this code, 80 bytes are allocated instead of 40. We ONLY need 40 bytes for the class yet 80 bytes get allocated; we can't use the myString variable until it gets its memory. This is wasted memory. How do I make it so that 40 bytes get allocated for the class and THEN the string variable gets its required memory by allocating itself 'on top of' the already allocated 40 bytes up front? I would assume we would have to get the address of the 40 bytes up front and then send that back to the class so that we could use placement new to then allocate the 40 bytes the string needs on top of this memory. Again, I am using a char pointer to better explain what I am trying to say.

Thanks - Lo$t

Share this post


Link to post
Share on other sites
That example does not create 40 bytes. It creates about 44 (on most systems).

Any *myClass - 4 bytes for the pointer.
= new Any(); - 0 bytes.
invokes ctor: Any() - 0 bytes.
new char[40] - 40 bytes.

Share this post


Link to post
Share on other sites
Quote:
Original post by Telastyn
That example does not create 40 bytes. It creates about 44 (on most systems).

Any *myClass - 4 bytes for the pointer.
= new Any(); - 0 bytes.
invokes ctor: Any() - 0 bytes.
new char[40] - 40 bytes.
Did you mean 'that example does not create 80 bytes'?

@The OP: As Telastyn noted, your example will allocate 40-some bytes on most systems, not 80. Where exactly are you getting the 80 from?

Share this post


Link to post
Share on other sites
It is my understanding that when new is invoked it uses the size_t parameter. So when myClass gets allocated, the sizeof(myClass) = 40. The same with the myString pointer. This is where I get 80 bytes from. Secondly are you saying that this is not how it happens? By the sounds of it you are saying that if I have a pointer member in my class memory does not get allocated until I allocate memory to each individual pointer variable myself. If this is the case then my interpretation of how C++ does memory allocation is wrong.

PS: I think this is how it is working. I overloaded operator new and had it print out the size_t parameter. It seems that when I do Any *myClass = new Any, and I have say 10 pointer variable members it is simply allocating the space for those 10 pointer variables, not the actual space for the variable itself. So if I have say a WNDCLASSEX pointer variable, Any *myClass = new Any will allocate space for the pointer to myClass and then space for the pointer for the WNDCLASSEX pointer. This is 8 bytes total. Now it is my job to allocate space for the actual variable at the pointer address for the WNDCLASSEX pointer (which is 48 bytes, sizeof(WNDCLASSEX) = 48).

Lo$t

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77
It is my understanding that when new is invoked it uses the size_t parameter. So when myClass gets allocated, the sizeof(myClass) = 40. The same with the myString pointer. This is where I get 80 bytes from. Secondly are you saying that this is not how it happens? By the sounds of it you are saying that if I have a pointer member in my class memory does not get allocated until I allocate memory to each individual pointer variable myself. If this is the case then my interpretation of how C++ does memory allocation is wrong.

Lo$t
The 40 bytes allocated in the 'Any' constructor is not included in the size of the 'Any' class. Here - take a look at the following slightly modified version of your program:

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

class Any
{
public:
char *myString;
Any(int numBytes);
};

Any::Any(int numBytes)
{
myString = new char[numBytes];
}

int main(void)
{
int numBytes;
std::cin >> numBytes;
Any *myClass = new Any(numBytes);
}


In the above program, what is the size of Any?

Share this post


Link to post
Share on other sites
Well if I had to guess given this new revelation, I would say it is 4 bytes because we have a pointer member variable (myString) which would be 4 bytes.

So the question is, when we have pointer class members we literally are allocating the memory for those pointers, 4 bytes each. Then it is our job to allocate the memory for each pointer variable calling new and THEN that will be the time when the actual memory gets handed out. So if I have char *myString, in the constructor when we do myString = new char[40], THIS is the only time when the actual 40 byte block of memory gets handed out. Correct me if I am wrong. Is this the way that all pointer data members are handled, so in a sense there is no wasted memory like I thought there was?

Lo$t

Share this post


Link to post
Share on other sites
Quote:
Original post by LostTime77
So the question is, when we have pointer class members we literally are allocating the memory for those pointers, 4 bytes each. Then it is our job to allocate the memory for each pointer variable calling new and THEN that will be the time when the actual memory gets handed out. So if I have char *myString, in the constructor when we do myString = new char[40], THIS is the only time when the actual 40 byte block of memory gets handed out. Correct me if I am wrong. Is this the way that all pointer data members are handled, so in a sense there is no wasted memory like I thought there was?

That sounds about right, yes.

However, ask yourself if you really need dynamic allocation here. Why not just store a WNDCLASSEX directly in your Any class? It saves you the trouble of new'ing and delete'ing it manually and it saves you a pointer (not that 4 bytes is a whole lot, but hey! ;)). And, on platforms with little memory, an additional advantage is that you avoid fragmenting memory.


Also, pointers do not always mean that you're dynamically allocating memory. Pointers can also simply point to already existing objects. Multiple pointers can be made to point to the same object (aliasing) or to nothing at all (NULL). In that sense, it's important to know what pointers indicate ownership (this pointer points to an object that I created, so I must also delete it through this pointer) and what pointers are used to refer to other objects (this pointer points to another object, but it's not created by me, so I must not delete it).

And that is where smart pointers become useful. Not only because they automate the memory management, but also because the kind of smart pointer that you're using tells you what exactly you intend to do there.

Share this post


Link to post
Share on other sites
Yeah alright. I understand it now. Plus I meant this as purely educational and as an example. It is not like I am going to turn right around and start dynamically allocating everything. I just wanted to understand how dynamic allocation works. A great big thanks to everybody for helping me!

Lo$t

Share this post


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

  • Advertisement