views:

219

answers:

3

Sorry if the question isn't clear; I found it pretty hard to explain in one sentence.

Say I have a struct with a member which is a struct, e.g. the following:

struct A {
    struct B b;
};

Lets say I intend instances of this structure to be heap-allocated always. Is there anything to be gained by changing it to this? (i.e. keeping a pointer to struct B)

struct A {
    struct B *b;
};

In the latter case I'd have a couple of functions such as make_A and free_A which would take care of allocating and de-allocating the memory pointed to by b;

The only example I can think of where the second form might be preferable is when not all instances of struct A will actually make use of b. In that case, memory could be saved by only allocating the extra memory for those instances which require it.

Are there any other cases where the second form offers something useful?

+8  A: 

If every A will have exactly one B, you should not use a pointer to B.

Besides the fact that you don't need to bother with the extra memory management, it's actually slower and less efficient to allocate B.

Even if you want to pass a pointer to B to other code, you can still pass that address.

Jason Cohen
+1 on less complex ot manage
ojblass
+5  A: 

When an instance of B can be shared by multiple instances of A you will gain by having a pointer to B. It helps to avoid duplication and maintaining versions of B in more than one place. Per Jonathan's comment this comes at a cost of knowing when to free the memory and couting references to B.

ojblass
At the cost of keeping track of who owns the pointer to B - or when it a given B can be freed. Reference counting in C++ terms.
Jonathan Leffler
+3  A: 

I think you've hit the nail on the head with your last statement. If not every A has a B, then you can gain memory saving by using a pointer (null for those As without a B).

This is unlikely to be really useful unless the cumulative size of all the unused Bs is a sizable proportion of the available heap.

But I would change your statement to read "when not all instances of A will have exactly one copy of B" for the following reason (and this is the other case you're asking for):

Where B is a node in a list (that also holds a pointer to another B or null), I would make it a pointer [although you could still embed the first node if all As had to have at least one B].

The other possibility is sharing Bs among the As if their nature permits it (such as A being a windows on a screen B), although you'd have to reference-count the Bs in that case so as to know when to finally free them in your free_A() calls (and, of course, being able to reuse an already-existing B in your make_A() calls).

paxdiablo