Topic: Does wrapping a struct around something change it?
Author: Jerry Leichter <leichter@smarts.com>
Date: 1998/12/03 Raw View
In general, any reinterpret_cast produces implementation-specific
results. However, consider the following case:
template <class T>
struct wrapped
{ T t;
};
...
wrapped<T>* w = new wrapped<T>[100];
T* t = reinterpret_cast<T*>(w);
Can one guarantee, under the standard, anything about t? In practice, I
know of no implementation in which there is any difference, other than
type, between w and t - or, for that matter, between an instance of T
and an instance of wrapped<T>. But is there an allowable interpretation
of the Standard under which this would not be true?
(I'm sure you're wondering why I want to do this. I'm trying to
instrument memory usage of a large program by providing every class with
a private new and delete which keeps some statistics. I have some
templated container classes which may account for a fair amount of
memory usage. The T above is the type of the elements of the container.
Usually, T is V* for some class V. V is instrumented, but of course T
(V*) is not, and can't be. I could laboriously modify every reference
inside the container implementation from x[i] to x[i].t, but that would
be painful - I want to instrument existing code, not code "kind of like"
the existing code!)
-- Jerry
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: RVerlinde@alva-bv.nl (Reinder)
Date: 1998/12/03 Raw View
In article <36669C65.66F2@smarts.com>, Jerry Leichter <leichter@smarts.com>
wrote:
>In general, any reinterpret_cast produces implementation-specific
>results. However, consider the following case:
>
>template <class T>
>struct wrapped
>{ T t;
>};
>
>...
> wrapped<T>* w = new wrapped<T>[100];
> T* t = reinterpret_cast<T*>(w);
>
>Can one guarantee, under the standard, anything about t? In practice, I
>know of no implementation in which there is any difference, other than
>type, between w and t - or, for that matter, between an instance of T
>and an instance of wrapped<T>. But is there an allowable interpretation
>of the Standard under which this would not be true?
>
I can see some possible problems with padding. Example: if sizeof( char) is
one byte, sizeof( wrapper<char>) might not be. If T is a struct, I would
expect sizeof( T) == sizeof( wrapper<T>), but I do not have the standard at
hand.
--
Reinder Verlinde
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1998/12/03 Raw View
Jerry Leichter wrote in message <36669C65.66F2@smarts.com>...
>
>In general, any reinterpret_cast produces implementation-specific
>results. However, consider the following case:
>
>template <class T>
>struct wrapped
>{ T t;
>};
>
>...
> wrapped<T>* w = new wrapped<T>[100];
> T* t = reinterpret_cast<T*>(w);
>
>Can one guarantee, under the standard, anything about t?
In theory, there's nothing you can count on. At an extreme, you can have a
standard-conforming C++ interpreter (or a debugging compiler) that adds
per-instance type information to each class.
In practice, I advise you to use a compile-time check that generates a
compil-time error if sizeof(wrapped<T>) is different from sizeof(T). The
code is well-known by now for the clcm readers, but I'll reproduce one
version of it just in case:
template <bool> class Checker;
template <> class Checker<true> {};
// in your code:
Checker<sizeof(wrapped<MyType>) == sizeof(MyType)> MyChecker;
If the sizes of the types are equal, I don't see much reason for which
reinterpret_cast shouldn't work. But I'm not very imaginative. I'm sure
there will be somebody who will come with something.
Anyway, because you live in the real world, just put the guard above,
document the stuff thoroughly and that's it.
Andrei
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/12/03 Raw View
"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
>Jerry Leichter wrote in message <36669C65.66F2@smarts.com>...
>>
>>In general, any reinterpret_cast produces implementation-specific
>>results. However, consider the following case:
>>
>>template <class T>
>>struct wrapped
>>{ T t;
>>};
>>
>>...
>> wrapped<T>* w = new wrapped<T>[100];
>> T* t = reinterpret_cast<T*>(w);
>>
>>Can one guarantee, under the standard, anything about t?
>In theory, there's nothing you can count on. At an extreme, you can have a
>standard-conforming C++ interpreter (or a debugging compiler) that adds
>per-instance type information to each class.
>In practice, I advise you to use a compile-time check that generates a
>compil-time error if sizeof(wrapped<T>) is different from sizeof(T).
That's too pessimistic a check. It is common for structs to
have a minimum size and alignment regardless of their contents.
For example, if T is char, the sizes are likely to be different.
For a POD-struct, you are allowed to convert a pointer to
the struct to a pointer to its first element, and vice versa.
Implementations are not allowed to add padding to the beginning
of a POD-struct.
If T is a POD-type, the reinterpret_cast is valid even if the
sizes of T and wrapped<T> are different. (A wrapped<T> cannot
have a less-strict alignment than a T, since they have the
same address.)
Those requirements don't hold for non-POD structs, and if T is
not a POD type, wrapped<T> is not a POD-struct. But is it unlikely
that an implementation would add padding ahead of the T member
of a wrapped<T> object. But if wrapped<T> had, for example, virtual
functions, the cast would be invalid on many systems. It is
common to put a vtable pointer at offset zero in the class.
As a practical matter, the cast is probably safe, although it
is not guaranteed for a non-POD type T.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1998/12/03 Raw View
Steve Clamage wrote in message <746vvb$eo3$1@engnews2.Eng.Sun.COM>...
>That's too pessimistic a check. It is common for structs to
>have a minimum size and alignment regardless of their contents.
>For example, if T is char, the sizes are likely to be different.
*** Steve,
Wait a minute! The initial poster wanted to cast from an *array* type to
another. I think you agree it is an absolute must for the sizes of types to
be exactly the same. Don't forget the initial code:
template <class T>
struct wrapped
{ T t;
};
...
wrapped<T>* w = new wrapped<T>[100];
T* t = reinterpret_cast<T*>(w);
If sizeof(wrapped<T>) != sizeof(T), t[99] won't access the 100th element of
the array.
Andrei
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/12/04 Raw View
"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
>Steve Clamage wrote in message <746vvb$eo3$1@engnews2.Eng.Sun.COM>...
>>That's too pessimistic a check. It is common for structs to
>>have a minimum size and alignment regardless of their contents.
>>For example, if T is char, the sizes are likely to be different.
>*** Steve,
>Wait a minute! The initial poster wanted to cast from an *array* type to
>another. I think you agree it is an absolute must for the sizes of types to
>be exactly the same. Don't forget the initial code:
Oops. Of course you are correct. I got stuck in the details of
what it meant to wrap a struct around another struct, and failed
to notice the array.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]