Topic: void* and T* layout compatibility?


Author: invalid@bigfoot.com (Bob Hairgrove)
Date: Wed, 10 Aug 2005 21:12:10 GMT
Raw View
On Fri, 24 Jun 2005 08:58:31 CST, "Me" <anti_spam_email2003@yahoo.com>
wrote:

>> you can assign a T* to a void* p and
>> then you can fetch that T* through a static_cast<T*>(p), but you can't
>> static_cast a pointer to void* to a pointer to T* or vice versa.

No. In both cases, use reinterpret_cast<T*> instead. Either way, the
compiler needs to know the size (and the binary representation)...

--
Bob Hairgrove
NoSpamPlease@Home.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ark@acm.org ("Andrew Koenig")
Date: Thu, 11 Aug 2005 05:31:11 GMT
Raw View
"Bob Hairgrove" <invalid@bigfoot.com> wrote in message
news:4iqkf119uikjmgdvr33s4okt755v93aj70@4ax.com...

>>> you can assign a T* to a void* p and
>>> then you can fetch that T* through a static_cast<T*>(p), but you can't
>>> static_cast a pointer to void* to a pointer to T* or vice versa.

> No. In both cases, use reinterpret_cast<T*> instead. Either way, the
> compiler needs to know the size (and the binary representation)...

How's that again?  If I have any pointer, I can convert it to void*,
static_cast it to the original type, and be assured of getting back the
original value.  If I use reinterpret_cast, I don't have that assurance.


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Mon, 27 Jun 2005 15:23:30 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:

>
> So anyway, to summarize the discussion in spite of whatever bumps in the
> road: it T is a generic type, using static_cast to convert T** <--->
> void**, as well as void*& <---> T*&, is verboten, for appropriately
> chosen definitions of "discussion", "<--->", and "verboten".
>

Well, yes, if by "verboten" you mean "allowed but non-conforming," which
Humpty Dumpty would find quite natural. But I'm really not interested in
feeding your word games any more.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Fri, 24 Jun 2005 09:01:50 CST
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:

    [...]
> > template <class T> class Vector<T*> : private Vector<void*> {

> >     typedef vector<void*> Base;
> >     T*& elem(int i) { return static_cast<T*&>(Base::elem(i)); }

> > };

> > I think this is in error and shouldn't compile for most Ts
> > (except char variants?). You can't cast void*& <---> T*&.

> The standard doesn't require that anything should or shouldn't
> compile (except maybe #error, but I'm not going to try to sort
> that out now), just that a conforming implementation must
> issue a diagnostic for any constraint violation.  With every
> compiler I've used this code works just fine.

It's not clear to me what you mean by "works just fine".  The
standard requires a diagnostic here.  Do you mean that every
compiler you've used issues a diagnostic, or that every compiler
you've used generated code which did what was wanted.  (Or both;
they're not incompatible.)

--
James Kanze                                           GABI Software
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


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@comAcast.net (Victor Bazarov)
Date: Fri, 24 Jun 2005 14:35:15 GMT
Raw View
Ron Natalie wrote:
> Pete Becker wrote:
>
>>
>> Yes, that's what I said. <g> "In general, they are identical..."
>>
>
> You are going to have to use a dictionary.   "In general" doesn't mean
> "In all cases I can think of" or "In most cases."  From the OED:
>
> "in general" -- In a body, collectively, universally, without exception.

That's one wrong dictionary you're using.  M-W puts 'in general' as the
synonym for 'generally' and 'usually', "as a rule", "in disregard of
specific instances and with regard to an overall picture".  So, it just
can't mean "without exception".

> [..]

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:03:49 GMT
Raw View
Ron Natalie wrote:

> Pete Becker wrote:
>
>>
>> Yes, that's what I said. <g> "In general, they are identical..."
>>
>
> You are going to have to use a dictionary.   "In general" doesn't mean
> "In all cases I can think of" or "In most cases."  From the OED:
>
> "in general" -- In a body, collectively, universally, without exception.
>

You are going to have to use a dictionary correctly. You left out: "(e)
For the most part; as a general rule; commonly, usually." I stand by my
statement: in general, pointer representations are the same, but the
standard doesn't require it.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:04:22 GMT
Raw View
Victor Bazarov wrote:

> Ron Natalie wrote:
>
>> Pete Becker wrote:
>>
>>>
>>> Yes, that's what I said. <g> "In general, they are identical..."
>>>
>>
>> You are going to have to use a dictionary.   "In general" doesn't mean
>> "In all cases I can think of" or "In most cases."  From the OED:
>>
>> "in general" -- In a body, collectively, universally, without exception.
>
>
> That's one wrong dictionary you're using.  M-W puts 'in general' as the
> synonym for 'generally' and 'usually', "as a rule", "in disregard of
> specific instances and with regard to an overall picture".  So, it just
> can't mean "without exception".
>

No, he's right, that's one of the meanings in the OED (Oxford English
Dictionary, one of the most respected authorities on the history and
meaning of English words). It's not the only one, though, and when
analyzing the technical content of other people's writing it's important
to look at all reasonable meanings rather than pick out the one that
supports your position. Reading objectively would greatly reduce the
amount of noise on newsgroups and help eliminate many misunderstandings
of C++ and programming in general ["in general" here meaning
"collectively,"].

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:05:20 GMT
Raw View
Me wrote:

>
> It shouldn't compile at all due to the rules about static_cast.         ]
>

It should issue a diagnostic. That's all that's required for a
constraint violation.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:05:12 GMT
Raw View
kanze@gabi-soft.fr wrote:

>
> It's not clear to me what you mean by "works just fine".  The
> standard requires a diagnostic here.  Do you mean that every
> compiler you've used issues a diagnostic, or that every compiler
> you've used generated code which did what was wanted.  (Or both;
> they're not incompatible.)
>

I said it too strongly. Should have been "would work just fine," becaues
the underlying representations are, in fact, the same.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:04:56 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:

> Pete Becker wrote:
>
>> Andrei Alexandrescu (See Website For Email) wrote:
>>
>
>>> I think this is in error and shouldn't compile for most Ts (except
>>> char variants?). You can't cast void*& <---> T*&.
>>>
>>
>> The standard doesn't require that anything should or shouldn't compile
>> (except maybe #error, but I'm not going to try to sort that out now),
>> just that a conforming implementation must issue a diagnostic for any
>> constraint violation. With every compiler I've used this code works
>> just fine.
>
>
> This might be some confusion. I've tried the following code:
>
> int main() {
>   void* p;
>   static_cast<int*&>(p) = new int;
> }
>
> with gcc 3.4.3 and MSVC 7.1. Both fail to compile, and I believe rightly
> so, given that "the layout might be different".
>

Having issued a diagnostic, the implementation is, in general ["in
general" here meaning "universally, without exception"] free to do
anything. In particular [i.e. in contradistinction to the previous
comment, which was "in general"], it is permitted to continue to compile
the offending code, which is the hook for implementation-specific
behavior. There is no requirement that code "shouldn't compile."

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 16:41:09 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:

>
> You also said the static_cast works on your compilers. Which compilers
> are those, or do you agree you were in error?
>

That was too broad a statement. What I meant was that it would work just
fine, because the pointer representations are, in fact, identical.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Fri, 24 Jun 2005 20:03:22 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>>
>> You also said the static_cast works on your compilers. Which compilers
>> are those, or do you agree you were in error?
>>
>
> That was too broad a statement. What I meant was that it would work just
> fine, because the pointer representations are, in fact, identical.

But it doesn't portably. The compilers emit a diagnostic, and then they
do whatever because the behavior is not defined.

So I think it's safe to actually say: "no, it doesn't work; compilers
emit a diagnostic and then they do something that is at best
nonportable, but on most, if not all, of today's compilers, they will
simply stop compilation and not generate anything".

Again: did you try the code with any compiler and got it to work?

On a different vein: to get the code to work, I'm thinking of a slightly
(but only slightly) safer solution: implement vector<T*> in terms of
vector<Undefined*>, where Undefined is, well, a
declared-but-never-defined class.

IIRC, all pointers to UDTs are layout compatible with one another. But
you still need to do reinterpret_cast because otherwise, well, you get
that diagnostic - not that there's anything wrong with it, the compiler
might continue etc. etc. :o)


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 20:34:02 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
>
> But it doesn't portably. The compilers emit a diagnostic, and then they
> do whatever because the behavior is not defined.

That's right.

>
> So I think it's safe to actually say: "no, it doesn't work; compilers
> emit a diagnostic and then they do something that is at best
> nonportable, but on most, if not all, of today's compilers, they will
> simply stop compilation and not generate anything".

Shrug. If your compiler doesn't compile it you have to come up with
something else. That's what porting code means.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Fri, 24 Jun 2005 22:36:03 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> So I think it's safe to actually say: "no, it doesn't work; compilers
>> emit a diagnostic and then they do something that is at best
>> nonportable, but on most, if not all, of today's compilers, they will
>> simply stop compilation and not generate anything".
>
>
> Shrug. If your compiler doesn't compile it you have to come up with
> something else. That's what porting code means.

I see. Is there a chance that the compiler emits a diagnostic (in the
form of a warning), compiles the code, but generates code that doesn't
behave as expected?

Also, for the 3rd time: what compilers did you get to generate code from
that static_cast?


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Fri, 24 Jun 2005 23:22:37 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
>
> I see. Is there a chance that the compiler emits a diagnostic (in the
> form of a warning), compiles the code, but generates code that doesn't
> behave as expected?

If you haven't checked what your implementation does (either by reading
the documentation or by testing) then it very likely doesn't behave as
you expect. The lesson, of course, is that if you shouldn't expect until
you've checked.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Sat, 25 Jun 2005 03:02:09 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>>
>> I see. Is there a chance that the compiler emits a diagnostic (in the
>> form of a warning), compiles the code, but generates code that doesn't
>> behave as expected?
>
>
> If you haven't checked what your implementation does (either by reading
> the documentation or by testing) then it very likely doesn't behave as
> you expect. The lesson, of course, is that if you shouldn't expect until
> you've checked.

To summarize: as far as static_cast<T**>(p) with p of type void** goes:

* The "works if it compiles, doesn't work if it doesn't compile"
strategy is not applicable.

* The strategy of testing, which you suggest, is eminently fishy. Maybe
the test works one way in one situation, and a different way in other
situations.

* Reading the documentation is the only resort, and one needs to
remember to go back to the code and change it if needed for each
platform they'd port to. The diagnostic might be of help there, because
I assume the programmer would look at the warnings when porting.

I don't see how this highly non-working and highly non-portable
technique could ever be recommendable.

Also, it looks like this is much ado for not a lot, because very few
compilers, if any, will even accept the code. Following your statement,
"With every compiler I've used this code works just fine", after I've
asked for three times which compilers are those to no avail, I assume
the response really is "Oops; the code doesn't work just fine on my
compilers just as it doesn't work on yours." Correct me if I'm wrong :o).


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Pete Becker <petebecker@acm.org>
Date: Sat, 25 Jun 2005 09:28:04 CST
Raw View
Andrei Alexandrescu (See Website For Email) wrote:

>
> To summarize: as far as static_cast<T**>(p) with p of type void** goes:
>

Summarizing something that hasn't been discussed is not a good way to
clarify a discussion.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Sat, 25 Jun 2005 17:00:06 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
>
> Also, it looks like this is much ado for not a lot, because very few
> compilers, if any, will even accept the code. Following your statement,
> "With every compiler I've used this code works just fine", after I've
> asked for three times which compilers are those to no avail, I assume
> the response really is "Oops; the code doesn't work just fine on my
> compilers just as it doesn't work on yours." Correct me if I'm wrong :o).
>

I can't stop you from assuming whatever you like. However, you might be
better able to persuade people if you based your assumptions on current
data. Basing them on statements that have been retracted makes it look
like your goal is not clarity, but victory.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Sun, 26 Jun 2005 01:03:19 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>>
>> To summarize: as far as static_cast<T**>(p) with p of type void** goes:
>>
>
> Summarizing something that hasn't been discussed is not a good way to
> clarify a discussion.

Looks like someone hasn't really followed the discussion :o). Quoting
from my post that started the discussion:

 > I understand a void* is guaranteed to hold any T* (except function and
 > member function pointers). However, in general void* is not layout
 > identical to T*, right? I mean, you can assign a T* to a void* p and
 > then you can fetch that T* through a static_cast<T*>(p), but you can't
 > static_cast a pointer to void* to a pointer to T* or vice versa.

100% match. Gotta love the Usenet - it's all there in writing, archived
for years to come.

By the way, I did find a compiler that accepts the cast: Digital Mars
C++. I have submitted a bug report to Walter.


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Sun, 26 Jun 2005 15:10:43 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
>
> 100% match. Gotta love the Usenet - it's all there in writing, archived
> for years to come.
>

Yup, 100%, since you snipped the code that was actually under
discussion. That code involved a static_cast to a reference to a
pointer. As you said in that message:

>> I think this is in error and shouldn't compile for most Ts (except char variants?).
 >> You can't cast void*& <---> T*&.

That's not a pointer to a pointer.

Gotta love the Usenet - it's all there in writing, archived for years to
come.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Mon, 27 Jun 2005 03:03:42 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>>
>> 100% match. Gotta love the Usenet - it's all there in writing,
>> archived for years to come.
>>
>
> Yup, 100%, since you snipped the code that was actually under
> discussion. That code involved a static_cast to a reference to a
> pointer. As you said in that message:

Hmm, let's go to that Usenet again and revisit what's been written (and
archived for years to come) :o). On 24 June, I wrote:

 > This might be some confusion. I've tried the following code:
 >
 > int main() {
 >   void* p;
 >   static_cast<int*&>(p) = new int;
 > }
 >
 > with gcc 3.4.3 and MSVC 7.1. Both fail to compile, and I believe rightly
 > so, given that "the layout might be different".
 >
 > test.cpp:3: error: invalid static_cast from type `void*' to type `int*&'
 >
 > Just to make sure, I got references out of the way by writing:
 >
 > int main() {
 >   void* p;
 >   *static_cast<int**>(&p) = new int;
 > }

This is a funny thread. It looks like some people not only don't follow
the discussion and give answers that require later refutation, but also
stick with the claim that they followed :o).

So anyway, to summarize the discussion in spite of whatever bumps in the
road: it T is a generic type, using static_cast to convert T** <--->
void**, as well as void*& <---> T*&, is verboten, for appropriately
chosen definitions of "discussion", "<--->", and "verboten".

It's becoming quite hard to filter through the noise. Thanks to those
who've participated with useful answers. I'm better outta here,
otherwise it happens like in soccer: a team gets ingrained in the play
of an obstructive adversary and instead of doing their usual play, they
start fouling just like the others.


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Thu, 23 Jun 2005 16:17:15 GMT
Raw View
I understand a void* is guaranteed to hold any T* (except function and
member function pointers). However, in general void* is not layout
identical to T*, right? I mean, you can assign a T* to a void* p and
then you can fetch that T* through a static_cast<T*>(p), but you can't
static_cast a pointer to void* to a pointer to T* or vice versa.

If that is the case, The C++ Programming language has an erratum that I
didn't find listed. On page 342, there is an implementation of
vector<T*> in terms of vector<void*>. The implementation offers
reference to element access by:

template <class T> class Vector<T*> : private Vector<void*> {
.
     typedef vector<void*> Base;
     T*& elem(int i) { return static_cast<T*&>(Base::elem(i)); }
.
};

I think this is in error and shouldn't compile for most Ts (except char
variants?). You can't cast void*& <---> T*&.


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Pete Becker <petebecker@acm.org>
Date: Thu, 23 Jun 2005 15:27:26 CST
Raw View
Andrei Alexandrescu (See Website For Email) wrote:

> I understand a void* is guaranteed to hold any T* (except function and
> member function pointers). However, in general void* is not layout
> identical to T*, right?

In general they are identical, although the standard doesn't require it.

> I mean, you can assign a T* to a void* p and
> then you can fetch that T* through a static_cast<T*>(p), but you can't
> static_cast a pointer to void* to a pointer to T* or vice versa.
>
> If that is the case, The C++ Programming language has an erratum that I
> didn't find listed. On page 342, there is an implementation of
> vector<T*> in terms of vector<void*>. The implementation offers
> reference to element access by:
>
> template <class T> class Vector<T*> : private Vector<void*> {
> .
>     typedef vector<void*> Base;
>     T*& elem(int i) { return static_cast<T*&>(Base::elem(i)); }
> .
> };
>
> I think this is in error and shouldn't compile for most Ts (except char
> variants?). You can't cast void*& <---> T*&.
>

The standard doesn't require that anything should or shouldn't compile
(except maybe #error, but I'm not going to try to sort that out now),
just that a conforming implementation must issue a diagnostic for any
constraint violation. With every compiler I've used this code works just
fine.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ron@spamcop.net (Ron Natalie)
Date: Thu, 23 Jun 2005 20:31:30 GMT
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
> I understand a void* is guaranteed to hold any T* (except function and
> member function pointers).

No, actually that's functions and poitners any sort of members.

> However, in general void* is not layout
> identical to T*, right? I mean, you can assign a T* to a void* p and
> then you can fetch that T* through a static_cast<T*>(p), but you can't
> static_cast a pointer to void* to a pointer to T* or vice versa.

Correct they are unrelated types.
>
> If that is the case, The C++ Programming language has an erratum that I
> didn't find listed. On page 342, there is an implementation of
> vector<T*> in terms of vector<void*>. The implementation offers
> reference to element access by:
>
> template <class T> class Vector<T*> : private Vector<void*> {
> .
>     typedef vector<void*> Base;
>     T*& elem(int i) { return static_cast<T*&>(Base::elem(i)); }
> .
> };
>
> I think this is in error and shouldn't compile for most Ts (except char
> variants?). You can't cast void*& <---> T*&.
>
Yep

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net
Date: 23 Jun 2005 21:20:02 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
> > I understand a void* is guaranteed to hold any T* (except function and
> > member function pointers). However, in general void* is not layout
> > identical to T*, right?
>
> In general they are identical, although the standard doesn't require it.

On some machines, hardware addressable storage units contain more than
one byte. On those machines, if sizeof(T) is a multiple of the size of
the addressable memory unit, T* is usually implemented as containing a
simple hardware address. Otherwise, T* must be implemented as a machine
address plus a byte offset within the storage unit identified by the
machine address, or by some equivalent mechanism. On such machines,
void* is generally not layout compatible with T* for most types.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: petebecker@acm.org (Pete Becker)
Date: Thu, 23 Jun 2005 22:10:56 GMT
Raw View
kuyper@wizard.net wrote:
> Pete Becker wrote:
>
>>Andrei Alexandrescu (See Website For Email) wrote:
>>
>>
>>>I understand a void* is guaranteed to hold any T* (except function and
>>>member function pointers). However, in general void* is not layout
>>>identical to T*, right?
>>
>>In general they are identical, although the standard doesn't require it.
>
>
> On some machines, hardware addressable storage units contain more than
> one byte. On those machines, if sizeof(T) is a multiple of the size of
> the addressable memory unit, T* is usually implemented as containing a
> simple hardware address. Otherwise, T* must be implemented as a machine
> address plus a byte offset within the storage unit identified by the
> machine address, or by some equivalent mechanism. On such machines,
> void* is generally not layout compatible with T* for most types.
>

Yes, that's what I said. <g> "In general, they are identical..."

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Fri, 24 Jun 2005 13:57:07 GMT
Raw View
Pete Becker wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>> I understand a void* is guaranteed to hold any T* (except function and
>> member function pointers). However, in general void* is not layout
>> identical to T*, right?
>
> In general they are identical, although the standard doesn't require it.

Ok, so that means "the layout might be different".

>> I think this is in error and shouldn't compile for most Ts (except
>> char variants?). You can't cast void*& <---> T*&.
>>
>
> The standard doesn't require that anything should or shouldn't compile
> (except maybe #error, but I'm not going to try to sort that out now),
> just that a conforming implementation must issue a diagnostic for any
> constraint violation. With every compiler I've used this code works just
> fine.

This might be some confusion. I've tried the following code:

int main() {
   void* p;
   static_cast<int*&>(p) = new int;
}

with gcc 3.4.3 and MSVC 7.1. Both fail to compile, and I believe rightly
so, given that "the layout might be different".

test.cpp:3: error: invalid static_cast from type `void*' to type `int*&'

Just to make sure, I got references out of the way by writing:

int main() {
   void* p;
   *static_cast<int**>(&p) = new int;
}

test.cpp:3: error: invalid static_cast from type `void**' to type `int**'

I agree with my compilers, and so I think page 342 of TC++PL is in
error. That code would require a reinterpret_cast, which won't work
portably.

So is it right to say that vector<T*> cannot be portably implemented by
using vector<void*> as a store? It could if vector<T*> would not expose
references to its elements, but it does, so...



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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jm@bourguet.org (Jean-Marc Bourguet)
Date: Fri, 24 Jun 2005 13:59:28 GMT
Raw View
kuyper@wizard.net writes:

> Pete Becker wrote:
> > Andrei Alexandrescu (See Website For Email) wrote:
> >
> > > I understand a void* is guaranteed to hold any T* (except function and
> > > member function pointers). However, in general void* is not layout
> > > identical to T*, right?
> >
> > In general they are identical, although the standard doesn't require it.
>
> On some machines, hardware addressable storage units contain more
> than one byte.

Could you name one such machine for which a modern C++ compiler is
available?  Well, even a ISO-90 C compiler would make the case.  I'm
under the impression that the C and C++ compilers for all modern
processors for which the unit of storage is not an octet use a byte
which is the unit of storage.

As a matter of fact, I'd be interested even by older machines for
which a C compiler existed.  I seem to remember that the C compiler
for the PDP-10 (which is the only C compiler I'm aware of for which
the byte was smaller that the storage unit -- it was even configurable
between 7, 8 and 9 bits byte -- I know the 7 bits byte is not
conforming) used the same format for void* than for other pointers.

Yours,

--
Jean-Marc

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com>
Date: Fri, 24 Jun 2005 08:57:30 CST
Raw View
Pete Becker wrote:
> kuyper@wizard.net wrote:
>
>> Pete Becker wrote:
>>
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>
>>>
>>>> I understand a void* is guaranteed to hold any T* (except function and
>>>> member function pointers). However, in general void* is not layout
>>>> identical to T*, right?
>>>
>>>
>>> In general they are identical, although the standard doesn't require it.
>>
>>
>> On some machines, hardware addressable storage units contain more than
>> one byte. On those machines, if sizeof(T) is a multiple of the size of
>> the addressable memory unit, T* is usually implemented as containing a
>> simple hardware address. Otherwise, T* must be implemented as a machine
>> address plus a byte offset within the storage unit identified by the
>> machine address, or by some equivalent mechanism. On such machines,
>> void* is generally not layout compatible with T* for most types.
>>
>
> Yes, that's what I said. <g> "In general, they are identical..."

You also said the static_cast works on your compilers. Which compilers
are those, or do you agree you were in error?

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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Me" <anti_spam_email2003@yahoo.com>
Date: Fri, 24 Jun 2005 08:58:31 CST
Raw View
> I understand a void* is guaranteed to hold any T* (except function and
> member function pointers). However, in general void* is not layout
> identical to T*, right? I mean, you can assign a T* to a void* p and
> then you can fetch that T* through a static_cast<T*>(p), but you can't
> static_cast a pointer to void* to a pointer to T* or vice versa.

Exactly. It also breaks aliasing rules.

> If that is the case, The C++ Programming language has an erratum that I
> didn't find listed. On page 342, there is an implementation of
> vector<T*> in terms of vector<void*>. The implementation offers
> reference to element access by:
>
> template <class T> class Vector<T*> : private Vector<void*> {
> .
>      typedef vector<void*> Base;
>      T*& elem(int i) { return static_cast<T*&>(Base::elem(i)); }
> .
> };
>
> I think this is in error and shouldn't compile for most Ts (except char
> variants?). You can't cast void*& <---> T*&.

It shouldn't compile at all due to the rules about static_cast. In this
case it would have to be bound to a temporary like
static_cast<T*const&>() and even if you were to cast away constness
(too tired to verify if this case is undefined or not), assignment to
that that temporary lvalue wouldn't modify the value stored in the
container. Even if you could make it work, the whole thing wouldn't be
correct due to aliasing rules anyway so I don't think this problem can
be solved in a standards conforming manner.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ron@spamcop.net (Ron Natalie)
Date: Fri, 24 Jun 2005 14:00:59 GMT
Raw View
Pete Becker wrote:

>
> Yes, that's what I said. <g> "In general, they are identical..."
>

You are going to have to use a dictionary.   "In general" doesn't mean
"In all cases I can think of" or "In most cases."  From the OED:

"in general" -- In a body, collectively, universally, without exception.

Now, as really meant, the rules say that while reiterpret cast does an
implementation defined mapping here it should be fairly obvious.  I've
worked on more odd-ball processors than most and I've dealt with screwy
pointer layouts, but I've never seen one that this shouldn't work on
either.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]