Re: operator== for aggregate types / member wise comparison
"Seungbeom Kim" <musiphil@bawi.org>
I know that, and I use them for what they're precisely meant for.
All I wanted to do was to log the event that happened. Are you
suggesting that such a logging should happen in another function?
How should that function be called during a copy construction or
an assignment?
What is the problem with putting the extra stuff in a properly named
function fuch as LoggedCopy() ;-)
That doesn't serve my purpose of logging every copy construction event.
I cannot control how the clients make a copy and change it, and I just
have to assume that the actual copy constructor is called everywhere.
As later turns out, as debug/development instrumentation, not for the
production code, IUC.
Please do not assume that I'm challenging you with a fictitious example;
wanting to log some event is a genuine need, and it helps little to say
"just don't do that" (assuming that's what you meant by "elimination").
I believe you :) just there IIRC this topic was about some general problem
wanting support. If your case -- despite taken from real life -- turns out
to be an exceptional, or knowing its real target, the language has a better
solution, would lead to different conlusions.
Really, I used traces time-to-time, but not in said functions -- a LOG
has
its use, but not on this technical level. {Unless, maybe if you have an
utter mess -- but it is likely an outcome of such ideas. }
I have had more than a case where I had to introduce a user-defined
copy constructor and enumerate all members just to do such a logging.
Okay, then you can tell the purpose and usefulness of why it was good,
and
what that log was used for. I am really curious.
Okay, to tell you the exact truth, I wanted to map every object with
a unique ID (other than its address) and log that (along with some
other member data) to facilitate debugging in later stages. AFAICS,
nowhere else than the constructors are the right places to do it.
Did it actually facilitate debugging? No pun, I'm really curious. I was
(and am) using such tracers, especially in weird environments (like this
moment I'm writing firmware for a PIC system, riddled with interrupts that
prevents use of a 'debugger' for practice, so traces and dumps are the main
tools to see what is happening.)
But I always think of them as a "wart" and they are made either removable by
macros or actually edited out as soon as not needed.
And certainly I wish for things that allow life without them ;)
And well, if there is an absolute need, then you go and maintain the list
of
members. No hunters - no hens, we don't have the perfect world. But a
language needs no tuning or support for some extreme cases.
It's just that it's hard for me to accept that it's such an extreme
case and that it's supposed to be so hard to solve.
I'd guess a language like C++ is better tuned for features for production
code. If I were in a committee deciding extension, I'd definitely demand
some use from that territory. As debug aids may seem "hard"
individually, but IMO collapse to a small set of cases with reusable
solutions. Very possibly some tool can be found on the net that generates
code or give a set of something that solves this
'object-lifetime-following'. Just as there are general tools like valgrind
working on a lower level.
It is hard indeed
with about a few dozen member variables (I wish it had fewer, but I
didn't write it, and I have to maintain it!), and the possibility of
a mistake of omitting some members is much more serious a burden than
the labour of enumerating all members.
IMO that is a very good motivation to NOT have the piece of code. What is
not there works good, and even saves read time. Destructors, auto-generated
operators are good. I srtive to keep and use them. The extra code need in
the rule-3 company is a smell, and make me look for rearrangement to use
some member or base class.
Especially, as I too often discovered bugs in the hand-written,
supposed-special-case implementation, something worked bad with exceptions,
or missed some symmetry. Listing all the members is the lightest of the
problems.
Btw if it's enough to drop a line in the log, it can be done using a
stateless member.
If just for instrumentation, I (likely) could create one that could call
the
enclosing class's Dump function too, so if placed properly at the end of
the
host, can do what you did above. (just from top of my head)
class Big;
template <class T>
struct LogTweak {
static void Log(const T * host);
const T * GetHostAddr() const;
LogTweak() { Log(GetHostAddr());}
LogTweak(const LogTweak &) { Log(GetHostAddr());}
};
class Big
{
public:
string State2String() { ... }
private:
// must be last member
LogTweak<Big> last;
};
Log() calls the host's renderer, no problem here.
GetHostAddr() is the tricky part, but with some ugly trick and casts the
address can be figured, having Big b; ptrdiff (char *) &b.last - (char
*)
&b; then using that offset substracted from this. the offsetof macro is
POD-only, but i'm sure there are general solutions providin it as
compile-time constant (and even the stock one shall work in practice for
regular members).
It's too ugly a trick as you admit, and I doubt if there are general
solutions, for: if there were one then why couldn't offsetof do it?
IIRC offsetof is a C legacy, and in C++ mandated to work POD only by the
standard. Certainly nothing forbids it working for more cases, and I'm sure
the stock thing is fine for majority of cases, only starts breaking with
some multiple and virtual inheritance cases. The last implementation I saw
was a simple substraction using null pointer. (What the implementation can
know to work fine.)
I guess there's something inherently unreliable that prevents offsetof
from being applicable entirely generally.
To me seem like an 'abandoned' thing, as in practice it works where has a
chance, however unofficially, while a full solution, that flag all the
problem cases as errors, AND giving an answer for the rest, and is also
meaningful, considering internal offsets... sounds like another 'not worth
bothering' case.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]