Wait a sec, checking Boost...
// Implementation by Alberto Barbati and Dave Harris.
#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
template <class T> std::size_t hash_value(T* const& v)
#else
template <class T> std::size_t hash_value(T* v)
#endif
{
std::size_t x = static_cast<std::size_t>(
reinterpret_cast<std:
trdiff_t>(v));
return x + (x >> 3);
}
Then reduction to the internally required range of the
particular hash table is the responsibility of that hash
table.
Of course. But the above isn't guaranteed to work, and I've
worked on systems where it wouldn't work. (By not working, I
mean that two pointers which compare equal will result in
different hash values.) I also know of one system where it is
almost useless. Where for any dynamically allocated complete
object, x would always have the same value. The above supposes
a one to one mapping between pointers and the integral types
involved, which is far from universal.
I also don't see why the double cast, rather than casting
directly to size_t, and the expression in the return statement
is a hack. If they're willing to restrict the function to
architectures with a one to one mapping, then they might as well
restrict it to architectures without any padding bits in
integral types as well, and just do a classical hash treating
the pointer as an array of bytes.
Some context must have disappeared here.
Maybe. I think you mentionned something about having to be sure
that the void* was obtained from the complete object, and not by
e.g. a static_cast of a pointer to a base class. The problem
being that converting pointers to different base classes of an
object may result in different void*. The problem with
callbacks is basically the same: a void* obtained by converting
from the address of the complete object may not be the same as
one obtained by converting from a pointer to a base class.
And you can cast from POD* to FirstMember*.
Yes. It's highly unlikely that POD or FirstMember have type
void. But I think you can go through a void* in those
conversions. (I'm not sure that the standard guarantees it, but
in practice, you surely can, given that the conversion without
passing through void* is legal, and converting to void* and back
to the original type must work.)
Especially because in practice, the erroneous code works in a
lot of cases. Until some change in an apparently unrelated part
(addition of a second base class to Derived, for example) causes
it to break.
Ouch in what sense? That you've got a lot of code using Boost,
and that converting it to the standard will be a lot of work?
The reasonning behind this is simple (sort of): a thread, per
se, has identity, and shouldn't be copiable (although the
standard version is movable). A thread identifier, however,
should be copiable, so it can be used in standard containers.
Do the C++0x threads require use of the rvalue stuff?
I don't think they require it. I imagine that there are some
cases where it might be useful, however. If nothing else, it
allows you to create a thread in a function and return it, so
that the calling code can do the join. Without movability
(which supposes rvalue references), you'd have to allocate it
dynamically, or give up identity, both of which have other
problems.
That is, have they re-designed the threads so that they break
existing code and can't be reasonably implemented in C++98?
Well, they can't break existing code, because no existing code
uses std::thread. And most of the library in the new standard
can't be implemented in C++98, because there are rvalue
references everywhere. (And of course, you can't implement
anything which uses threads in C++98
. But I know what you
mean.) On the other hand, you should be able to implement most
of the interface in C98, with the exception of the movability
stuff.
What do you mean by "detached thread"?
One that can't be joined. Under Unix, one on which you've
called pthread_detach. Under Windows (I think), one on which
you've closed all handles to it. In other words, the opposite
of a joinable thread.
Uh, are you saying that someone is seriously considering
/copying/ threads?
Not the object of thread type. But a thread executes code: in
C++, a functional object. And that gets copied (at least in
Boost). And that copy must occur in a thread safe manner; you
can't return from starting the thread (the constructor of thread
in the case of Boost and std::thread) before the copy has
finished, in the newly started thread. Which means (at least in
the case of Boost---there may be other solutions, but I'm not
familiar with them) an additional condition variable, and a
wait.
In the case of a joinable thread, this is typically not what is
wanted; the functional object will remain alive (but untouched
by the original thread) until after the join has finished, at
which time, the original thread will access the data in the
functional object which was modified by the joined thread. In
practice, the copy isn't a big problem; you just add a level of
indirection in the functional object (which contains a pointer
to the data object, rather than the data itself). But the extra
synchronization may have a performance impact on some systems,
e.g. in cases where threading is being used to parallelize
operations on a multi processor system.