 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Dave Moore Guest
|
Posted: Tue Jan 18, 2005 11:09 pm Post subject: wisdom of using const references as data members |
|
|
I have been using const references as data members in my classes for some
time now, and although I don't seem to have any problems thus far, it still
gives me the willies. This is because the external object referred to may
change its state "unexpectedly" (i.e. without announcing itself),
potentially changing the behavior of the enclosing class in a "silent"
fashion. (I am also familiar with object lifetime issues which can
potentially create dangling references, so that is not really what I am
trying to get at in this post.) I am about to make a major upgrade to one
of my programs, for which my current design involves introducing several
more classes that have const reference members. Before I do this, I wanted
to step back and review the general wisdom of the technique.
It certainly seems like there are times when using const reference members
is "the right thing to do", for example when it helps you to avoid exposing
the implementation of a class. Consider the following example, where the
implementation of a particular type of calculation requires a helper class,
which is not part of its public interface. This suggests enclosing a helper
object in the class as a data member, as opposed to passing a reference as
an argument. However, when several calculation objects can be "helped" by
the same helper object, it does not make sense to store a copy in each
calculation object. Thus we arrive at:
class calculation {
public:
calculation(const helper& h) : _helper(h) {}
// ...
private:
const calc_helper& _helper; // calculation does not modify _helper
};
With this design we also get the automatic "optimization" that when we
change the external helper object, it is instantly updated in all of the
calculation objects (which is the particular reason I am expending effort to
make this technique work in my code). Of course this "tight coupling" of
the helper and calculation objects (not classes) is a double-edged sword,
because it can introduce order of execution dependencies into the code,
which may then pop up at run-time in mysterious ways.
So my question is, are there any idioms or patterns out there for handling
(or even eliminating) the use of const references as data members in a safe
way, or at least in the safest possible way? I have searched around in my
books and on the web and I have not been able to find anything particularly
useful. Any suggestions?
TIA,
Dave Moore
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Matthew Herrmann Guest
|
Posted: Wed Jan 19, 2005 11:56 pm Post subject: Re: wisdom of using const references as data members |
|
|
Dave Moore wrote:
| Quote: | I have been using const references as data members in my classes for
some
time now, and although I don't seem to have any problems thus far, it
still
gives me the willies. This is because the external object referred
to may
change its state "unexpectedly" (i.e. without announcing itself),
potentially changing the behavior of the enclosing class in a
"silent"
fashion. (I am also familiar with object lifetime issues which can
potentially create dangling references, so that is not really what I
am
trying to get at in this post.) I am about to make a major upgrade
to one
of my programs, for which my current design involves introducing
several
more classes that have const reference members. Before I do this, I
wanted
to step back and review the general wisdom of the technique.
It certainly seems like there are times when using const reference
members
is "the right thing to do", for example when it helps you to avoid
exposing
the implementation of a class. Consider the following example, where
the
implementation of a particular type of calculation requires a helper
class,
which is not part of its public interface. This suggests enclosing a
helper
object in the class as a data member, as opposed to passing a
reference as
an argument. However, when several calculation objects can be
"helped" by
the same helper object, it does not make sense to store a copy in
each
calculation object. Thus we arrive at:
class calculation {
public:
calculation(const helper& h) : _helper(h) {}
// ...
private:
const calc_helper& _helper; // calculation does not modify
_helper
};
With this design we also get the automatic "optimization" that when
we
change the external helper object, it is instantly updated in all of
the
calculation objects (which is the particular reason I am expending
effort to
make this technique work in my code). Of course this "tight
coupling" of
the helper and calculation objects (not classes) is a double-edged
sword,
because it can introduce order of execution dependencies into the
code,
which may then pop up at run-time in mysterious ways.
So my question is, are there any idioms or patterns out there for
handling
(or even eliminating) the use of const references as data members in
a safe
way, or at least in the safest possible way? I have searched around
in my
books and on the web and I have not been able to find anything
particularly
useful. Any suggestions?
|
The key issue is this: "calculation" is in a dependency relationship
with "helper". There are fields, which, whenever helper changes, must
be updated. You could draw these relationships on a sheet of paper with
a graph. You need to make sure that whenever the source changes, the
dependent updates change. The naiive way to do this is to use the
Listener design pattern, and recalculate on all changes.
The better way is to use a "late-as-possible" update approach which
only updates the target on first access to the calculated results:
* Source changes
* Source notifies target
* Target sets dirty flag to true
* Before accessing any calculated values in target, the dirty flag is
checked. If the dirty flag is true, then recalculate and set to false.
This approach is particularly important in deeply embedded hierarchies
where nested Listener connections cause spiralling performance hits.
The "late-as-possible" approach also prevents unintended calculations
being kicked off in destructors.
HTH,
Matthew Herrmann
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|