Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

type punning

0 views
Skip to first unread message

goodfella

unread,
Sep 4, 2008, 1:54:25 PM9/4/08
to
I am curious about creating some macro's for keeping track of where
memory has been allocated on the heap. For example it would be nice
to be able to detect memory leaks at the end of program execution. I
would like a system that does not incur to much size and speed
overhead. Here is my design for a way to manage who created what and
where:

#ifndef HEAP_OBJECT_H
#define HEAP_OBJECT_H

struct code_loc
{
code_loc(const char* f, const char* fu, int l):
file(f), func(fu), line(l)
{}

const char* file;
const char* func;
int line;
};

template<class T>
class heap_object
{
public:
heap_object(const T&, const struct code_loc&);

T obj;
struct code_loc loc;
};

template<class T>
heap_object<T>::heap_object(const T& p, const struct code_loc& l):
obj(p), loc(l)
{}

#endif

The macros that implement the system are as follows:
#define track_new(init) (typeof(init)*)new
heap_object<typeof(init)>(init,code_loc(__FILE__,__PRETTY_FUNCTION__,__LINE__))

#define track_delete(pointer) delete
(heap_object<typeof(*pointer)>*)pointer

So basically I have a template class whose first data member is an
object of the type that I want to create. My assumption is that the
offset to this member is zero, so by type casting the pointer to the
heap_object to the type I want; I would have a valid pointer to the
type I want. So my first question is,

"Is it a safe assumption that the first data member of a class always
has an offset of zero?"

I have ran some limited tests with valgrind and it does not seem to
detect memory errors or leaks. I figure as long as I can insure that
track_delete is only called on objects created with track_new the code
is ok. Of course I will need some kind of list to keep track of what
has and has not been deleted, as well as be able to remove objects
from such a list that have been deleted in O(1) time. I think I have
that solved but of course the whole system is dependent on my
assumption above. Any help would be appreciated thanks.

Victor Bazarov

unread,
Sep 4, 2008, 2:02:09 PM9/4/08
to
goodfella wrote:
> [..] So my first question is,

>
> "Is it a safe assumption that the first data member of a class always
> has an offset of zero?"

Only for classes that do not derive from any other UDT _and_ do not have
any virtual functions.

> [..]

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

goodfella

unread,
Sep 4, 2008, 2:10:05 PM9/4/08
to

So since my template class does not derive from any other UDT and does
not have any virtual functions, it is safe to assume that its first
data member has an offset of zero and thus a pointer to the data
member points to the same address as a pointer to the object which
contains the data member.

Victor Bazarov

unread,
Sep 4, 2008, 2:12:39 PM9/4/08
to

I don't know of any implementation that would put anything else between
the first non-static data member and the beginning of the object. I am
too lazy to check with the Standard if it requires the addresses to be
the same, though.

gpderetta

unread,
Sep 4, 2008, 2:21:34 PM9/4/08
to
On Sep 4, 8:12 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> goodfella wrote:
> > On Sep 4, 11:02 am, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> >> goodfella wrote:
> >>> [..]  So my first question is,
> >>> "Is it a safe assumption that the first data member of a class always
> >>> has an offset of zero?"
> >> Only for classes that do not derive from any other UDT _and_ do not have
> >> any virtual functions.
>
> >>> [..]
> >> V
> >> --
> >> Please remove capital 'A's when replying by e-mail
> >> I do not respond to top-posted replies, please don't ask
>
> > So since my template class does not derive from any other UDT and does
> > not have any virtual functions, it is safe to assume that its first
> > data member has an offset of zero and thus a pointer to the data
> > member points to the same address as a pointer to the object which
> > contains the data member.
>
> I don't know of any implementation that would put anything else between
> the first non-static data member and the beginning of the object.  I am
> too lazy to check with the Standard if it requires the addresses to be
> the same, though.
>

AFAIK at least for POD is required.

--
gpd

Victor Bazarov

unread,
Sep 4, 2008, 2:33:41 PM9/4/08
to

Can you be/make sure your template is POD?

goodfella

unread,
Sep 4, 2008, 2:43:32 PM9/4/08
to

I apologize for my ignorance, but what does POD stand for?

goodfella

unread,
Sep 4, 2008, 2:55:06 PM9/4/08
to

So it seems that I cannot insure that my template class is POD;
however, does the fact that it has a constructor, and a non-POD data
member mean that there will be something else between the first non-
static data member?

Victor Bazarov

unread,
Sep 4, 2008, 3:45:32 PM9/4/08
to

Plain Old Data.

> So it seems that I cannot insure that my template class is POD;
> however, does the fact that it has a constructor, and a non-POD data
> member mean that there will be something else between the first non-
> static data member?

No, but it does break the contract between the language and you, the
compiler does *not* have to provide you with a particular layout, and so
you shouldn't rely on it. In most cases you will not find anything else
between the beginning of the object and its first non-static data, but
the guarantee does not exist, all bets are off.

Pascal J. Bourguignon

unread,
Sep 5, 2008, 4:17:40 AM9/5/08
to
goodfella <goodfe...@gmail.com> writes:

> I am curious about creating some macro's for keeping track of where
> memory has been allocated on the heap. For example it would be nice
> to be able to detect memory leaks at the end of program execution. I
> would like a system that does not incur to much size and speed
> overhead.

Use valgrind.


> "Is it a safe assumption that the first data member of a class always
> has an offset of zero?"

No.


> I have ran some limited tests with valgrind and it does not seem to
> detect memory errors or leaks.

Perhaps you didn't use it properly. Here it works very well.


% cat bug.c++

#include <iostream>
using namespace std;

class A{
public:
int x;
virtual ~A(){}
virtual int getX(){return x+1;}
};

int main(void){
A* a=new A;
A* b=a;
A* c=new A;

cout<<"offset of x = "<<((char*)(&(a->x)))-((char*)a)<<endl;
delete a;
delete b;
return(0);
}

/*
-*- mode: compilation; default-directory: "~/src/tests-c++/" -*-
Compilation started at Fri Sep 5 10:15:51

SRC="/home/pjb/src/tests-c++/bug.c++" ; EXE="bug" ; g++ -I$HOME/opt/libanevia-1.0.0-trunk//include/libanevia-1.0/ -L$HOME/opt/libanevia-1.0.0-trunk//lib/libanevia-1.0/ -Lanevia -g3 -ggdb3 -o ${EXE} ${SRC} && valgrind --tool=memcheck ./${EXE} && echo status = $?
==12256== Memcheck, a memory error detector.
==12256== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==12256== Using LibVEX rev 1854, a library for dynamic binary translation.
==12256== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==12256== Using valgrind-3.3.1, a dynamic binary instrumentation framework.
==12256== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==12256== For more details, rerun with: -v
==12256==
offset of x = 8
==12256== Invalid read of size 8
==12256== at 0x400A9E: main (bug.c++:18)
==12256== Address 0x58e9030 is 0 bytes inside a block of size 16 free'd
==12256== at 0x4C2086C: operator delete(void*) (vg_replace_malloc.c:342)
==12256== by 0x400B0D: A::~A() (bug.c++:7)
==12256== by 0x400A92: main (bug.c++:17)
==12256==
==12256== Invalid write of size 8
==12256== at 0x400AF9: A::~A() (bug.c++:7)
==12256== by 0x400AAD: main (bug.c++:18)
==12256== Address 0x58e9030 is 0 bytes inside a block of size 16 free'd
==12256== at 0x4C2086C: operator delete(void*) (vg_replace_malloc.c:342)
==12256== by 0x400B0D: A::~A() (bug.c++:7)
==12256== by 0x400A92: main (bug.c++:17)
==12256==
==12256== Invalid free() / delete / delete[]
==12256== at 0x4C2086C: operator delete(void*) (vg_replace_malloc.c:342)
==12256== by 0x400B0D: A::~A() (bug.c++:7)
==12256== by 0x400AAD: main (bug.c++:18)
==12256== Address 0x58e9030 is 0 bytes inside a block of size 16 free'd
==12256== at 0x4C2086C: operator delete(void*) (vg_replace_malloc.c:342)
==12256== by 0x400B0D: A::~A() (bug.c++:7)
==12256== by 0x400A92: main (bug.c++:17)
==12256==
==12256== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 1)
==12256== malloc/free: in use at exit: 16 bytes in 1 blocks.
==12256== malloc/free: 2 allocs, 2 frees, 32 bytes allocated.
==12256== For counts of detected errors, rerun with: -v
==12256== searching for pointers to 1 not-freed blocks.
==12256== checked 162,136 bytes.
==12256==
==12256== LEAK SUMMARY:
==12256== definitely lost: 16 bytes in 1 blocks.
==12256== possibly lost: 0 bytes in 0 blocks.
==12256== still reachable: 0 bytes in 0 blocks.
==12256== suppressed: 0 bytes in 0 blocks.
==12256== Rerun with --leak-check=full to see details of leaked memory.
status = 0

Compilation finished at Fri Sep 5 10:15:52

*/


--
__Pascal Bourguignon__

James Kanze

unread,
Sep 5, 2008, 4:52:14 AM9/5/08
to
On Sep 4, 8:02 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> goodfella wrote:
> > [..] So my first question is,

> > "Is it a safe assumption that the first data member of a
> > class always has an offset of zero?"

> Only for classes that do not derive from any other UDT _and_
> do not have any virtual functions.

Officially, only for POD's, I think. As soon as there is an
access specifier, at least, the compiler is allowed to reorder
elements with different access specifiers.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze

unread,
Sep 5, 2008, 4:56:58 AM9/5/08
to

> #ifndef HEAP_OBJECT_H
> #define HEAP_OBJECT_H

> #endif

Since you need to explicitly specify when your tracking system
is being used, in the allocation and the deletion, why not use
the classical solution, with placement new. Something like:

#define track_new new( __FILE__, __LINE__ )

?

goodfella

unread,
Sep 5, 2008, 10:59:52 AM9/5/08
to
On Sep 5, 1:17 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

Thanks Pascal, but I wasn't saying that valgrind did not work at all,
I was just commenting on the fact that with the code I supplied and
limited testing, valgrind was not producing errors, which was what I
expected given the limited scope of my tests. I have used valgrind
before for other projects and it helped to eliminate memory leaks and
errors.

goodfella

unread,
Sep 5, 2008, 4:33:09 PM9/5/08
to
> James Kanze (GABI Software) email:james.ka...@gmail.com

> Conseils en informatique orientée objet/
> Beratung in objektorientierter Datenverarbeitung
> 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


I wanted something that can go through and tell me what has not been
deleted; not just where something was created

0 new messages