Re: Associating C++ new with constructor

Michael Veksler
2007-02-15T20:29:39Z

Ross Boylan wrote:
...
> On Thu, Feb 15, 2007 at 03:35:14PM +0200, Michael Veksler wrote:
>
>> The idea is simple, and took me less than a day to implement:
>> Define a template class that can monitor object creation and
>> destruction.
>> Insert a member of this type into all non-POD classes:
>> class MyFoo {
>> ....
>> ....
>> ...
>> Count<MyFoo> m_count_for_MyFoo;
>> };
>>
The difficulty with this, is that it will work reliably only for
non-POD classes. For POD (Plain Old Data) classes or
structs, you are not allowed to automatically modify them,
because they might participate in code such as
struct A {
int a, b;
};
void Serialize(ostream & out, const A& a) {
out.write(reinterpret_cast<const char*>(&a), sizeof(a));
}

This is well defined only if A is a POD, if you add a Count
instance then the program becomes:
1. undefined
2. outputs wrong stuff to the stream.
> One nice thing about this vs. the memory corruption detection tools is
> that it catches all instance creation, not just stuff on the heap.
>
And that's one of the reason it is still used used despite of other tools.
>> It is imperfect since it can't reliably detect all
>> non-POD classes, and it does not work for std::***
>> classes. To make it 100% reliable, I had to write
>> a complete C++ parser!.
>>
>
> Why isn't this reliable for all classes in your source code (at least
> if you add a search for "struct")? Are you referring to cases that
> use pre-processor magic, or is there something else?
>
Read my comment above about the importance of non-POD checks.
There is no preprocessor magic, only a trivial perl script that inserts
instances into non-POD classes. The inaccuracy comes from

1. It is difficult to find all definitions of all classes. You should
ignore
occurrences of the "class" word in strings and in /* */ comments.
You should find "class" words expanded by some user macros.
This is virtually impossible to get right without at least running
a preprocessor.
2. It is difficult to be certain that some class is a non-POD class,
since its POD-ness depends also on its parents and members.
Also, user's macros may hide stuff, like virtual methods.
Templates make it even more difficult.

I simply made some dumb assumptions in my script that all "class"
definitions are non-POD (or at least never used as POD), and
all "struct" definitions are suspected to be POD. Fortunately,
this assumption is correct most of the time due to common
coding conventions.
> Another approach is in libcwd, which records the class along with the
> memory allocation if you insert a call to AllocTag() after the call to
> new. AllocTag uses templates under the hood to get the type of the
> pointer automatically, and libcwd provides a macro NEW that will take
> care of it automatically, e.g., A *pA = NEW(A()).
>
So you have to write your code this way, or write a preprocessor script
to modify

A *pA= new A(new B, new C[5]));

to

A *pA= NEW(NEW(B), NEW_ARRAY(C, 5));

(I just guess how new over an array are done, I don't really use libcwd).
> This problem was driving me crazy enough that I was looking into
> putting hooks in gcc, which has the advantage of providing a C++
> parser. That approach has a few disadvantages. Aside from being a
> big project (at least for someone like myself who knows little about
> compilers), it would be impractical to redistribute.
>
I don't think there should be any problem to redistribute such a tool.
I know of at least one such project.

--
Michael Veksler