Checking for null pointer for structure

A

Alf P. Steinbach

* Noah Roberts:
I wouldn't agree. There are several things I see with this solution
that make me question it.

1 - Although the OP used "NestedStruct" as his name, he didn't actually
nest it. There's nothing here that tells us that there's no use for
"NestedStruct" outside of "TopStruct".

2 - We don't know that even if #1 is as we are assuming (only used
within the context of TopStruct) that it will continue to be so.

3 - TopStruct cannot be used as a value type except when it doesn't have
the "NestedStruct". It must always use pointer semantics.

For 1, if that is a problem, you simply don't make NestedStruct directly the
derived class but rather the derived class will have such a member

2 is IMHO a good point, but it depends on whether the NestedStruct is meaningful
on its own.

For 3 the "cannot" is incorrect -- note the assumption of staying the same way
during lifetime -- but using Boost optional is as you point out far more
convenient when that assumption does not hold /and/ you want value semantics.

Summing up, if there is a good chance that NestedStruct might be useful on its
own in the future, it should perhaps be written as a separate class.

But on the other hand, premature generalization can lead to wasted work, so it
depends on the concrete case and to some degree personal preference.

The first and second problem are not inherent problems, at least not in
this very specific case (could be in other cases), but it does force all
clients of "NestedStruct" to also hold uninteresting information
inherited from "TopStruct".

The third issue may or may not come up, but there's no reason to force
pointer semantics on something that doesn't necessarily need it.

You may buy some pointer safety with this design but there's a better
option that will provide that same safety without the inheritance,
dynamic_cast, and will give the OP what we should always prefer over
inheritance: composition. That better method is boost::eek:ptional.

struct NestedStruct { std::string x; };
struct TopStruct
{
std::string ggg;
boost::eek:ptional<NestedStruct> nested;
};

while ( top = GetStructs() )
{
if (top->nested)
do_things_with_nested(*top->nested);
}

This solution is very nice, especially when one is already using Boost.

It does introduce a dependency on Boost, but 'optional' isn't difficult to
create from scratch.


Cheers,

- Alf
 
N

Noah Roberts

* Noah Roberts:

For 1, if that is a problem, you simply don't make NestedStruct directly the
derived class but rather the derived class will have such a member

2 is IMHO a good point, but it depends on whether the NestedStruct is meaningful
on its own.

For 3 the "cannot" is incorrect -- note the assumption of staying the same way
during lifetime -- but using Boost optional is as you point out far more
convenient when that assumption does not hold /and/ you want value semantics.

Summing up, if there is a good chance that NestedStruct might be useful on its
own in the future, it should perhaps be written as a separate class.

But on the other hand, premature generalization can lead to wasted work, so it
depends on the concrete case and to some degree personal preference.

I wouldn't call it "premature generalization". In fact, with simple
composition it's hard to call it 'generalization' at all. At any rate,
no matter whether we agree to call it "premature generalization" or not,
truth is that it doesn't actually add any extra work. Either you write
a subclass or you write an external class. Either you check for the
existence of "NestedStruct" through dynamic cast, or an optional check
(or some other compositional check). In both cases the amount of effort
is nearly the same if not exactly the same.

On the other hand, if when all other things are equal we prefer
inheritance rather than composition we can actually run into quite a few
problems from a variety of directions. For example, what if we end up
needing a new TopStruct type that adds or overrides behavior? Currently
we're working with TopStruct with the assumption that it may or may not
have a NestedStruct, and the new subclass would probably need the same
behavior. Thus we'd need to override twice instead of once such that
for each override of TopStruct you've got 2 classes to create. This can
get worse.

In other words, I missed a fourth reason to prefer composition.

Finally, as to the value type thing. You are right. I used incorrect
terms. What I meant is that you'll not be able to use a TopStruct as a
value_type in a container while retaining the behavior that we're
looking at here. You'd be required to use pointer semantics in this and
similar cases. "vector = WithNested(x)" would not do what we want.
Case by case basis of course, but I'd view this as pretty problematic
given that "WithNested" appears to be a particular state of a TopStruct
even if it is a permanent one. In other words, I took "lifetime of the
object" to mean "lifetime of the identity the object represents", which
is technically incorrect but still important.

So, I'm not saying there might not be reasons we can't see to do it your
way but given what is given I think my approach is better: it's not
increasing the generalization since, as you can see, the same behaviors
are available in both cases; it's not really increasing any work unless
you have to roll optional from scratch (which is minor and provides
another very useful class); it allows value storage in containers; and
it's a difference that could pay off later.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,157
Latest member
MercedesE4
Top