From: Sal on
Alright, so I've been working on a monitoring class for a little while now
and I realized that the way I am maintaining my internal references to the
monitored class may not be the most obvious to users. Perhaps let me explain
how I am doing it now, and then I'd be welcome to suggestions to alternative
approaches. Imagine you have two classes, ClassA, and ClassB. ClassA is just
some class that changes its internal state from time to time, and ClassB is
a class that provides additional content, based on the current state of a
ClassA instance (it actually provides significant analysis that is
independent of ClassA, so it really doesn't make sense to merge the two
classes). So, ClassB essentially needs to contain an internal reference to a
ClassA object:

class ClassA;

class ClassB
{
ClassA *myItem;
public:
ClassB(const ClassA &item)
: myItem(&item) { }
}

I'm sure you see the problem with this immediately; although the intention
is for the user to "new" a ClassA and pass it into the constructor to ClassB
(that way the internal pointer of ClassB won't change), the constructor
takes in a reference. Which means theoretically the user could create a
ClassA on the stack, pass it to a ClassB, then have it deleted and now the
ClassB points to garbage. Alternatively, it could be written as:

class ClassB
{
ClassA *myItem;
public:
ClassB(const ClassA *item)
: myItem(item) { }
}

But, I'm under the impression that passing pointers around probably isn't
the best practice (in general). So, I guess my question is which one makes
more sense from an outside user's standpoint (or does neither make sense)?
There isn't much chance of getting around keeping an internal pointer, and
obviously I know that it will be fragile (since whomever passed in the
ClassA to begin with has free reign to destroy the object at will), but I'm
looking for the best practice so that the consumer of ClassB will think:
"hey, this ClassB is storing an internal reference, maybe I shouldn't delete
this ClassA".

- Sal


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Martin B. on
On 26.02.2010 10:35, Sal wrote:
> Alright, so I've been working on a monitoring class for a little while now
> and I realized that the way I am maintaining my internal references to the
> monitored class may not be the most obvious to users.(....)
> So, ClassB essentially needs to contain an internal reference
> to a
> ClassA object:
>
> class ClassA;
>
> class ClassB
> {
> ClassA *myItem;
> public:
> ClassB(const ClassA &item)
> : myItem(&item) { }
> }
>
> I'm sure you see the problem with this immediately; although the intention
> is for the user to "new" a ClassA and pass it into the constructor to
> ClassB
> (that way the internal pointer of ClassB won't change), the constructor
> takes in a reference. Which means theoretically the user could create a
> ClassA on the stack, pass it to a ClassB, then have it deleted and now the

Don't EVER use const-references for this. See a recent thread started by
me:
http://compgroups.net/comp.lang.c++.moderated/Why-you-should-never-use-a-const-parameter-to-initialize-a-const-member


> ClassB points to garbage. Alternatively, it could be written as:
>
> class ClassB
> {
> ClassA *myItem;
> public:
> ClassB(const ClassA *item)
> : myItem(item) { }
> }
>
> But, I'm under the impression that passing pointers around probably isn't
> the best practice (in general). So, I guess my question is which one makes
> more sense from an outside user's standpoint (or does neither make sense)?

Well, using a pointer to track an external entity makes absolute sense
in C++ to me so I think this solution is quite OK.

> There isn't much chance of getting around keeping an internal pointer, and
> obviously I know that it will be fragile (since whomever passed in the
> ClassA to begin with has free reign to destroy the object at will), but I'm
> looking for the best practice so that the consumer of ClassB will think:
> "hey, this ClassB is storing an internal reference, maybe I shouldn't
> delete
> this ClassA".
>

While a shared_ptr or weak_ptr may be a good tool here, it may also be
that it's overkill (not performance or something - just the complexity
of introducing the smart ptr type)
If you have to construct ClassB with a ClassA object, for me it's
absolutely OK to have a comment/requirement stating that ClassB will
track ClassA and any operation involving ClassB is only defined if
ClassA isn't destroyed. I find that this is often sufficient.

br,
Martin

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]