Boost logo

Boost :

From: Philippe A. Bouchard (philippeb_at_[hidden])
Date: 2002-08-08 09:13:26


"David B. Held" <dheld_at_[hidden]> wrote in message
news:aist0a$oij$1_at_main.gmane.org...
> "Philippe A. Bouchard" <philippeb_at_[hidden]> wrote in message
> news:aisoeh$hau$1_at_main.gmane.org...
> > [...]
> > Well this issue is based purely on the fact that an integer is always
the
> > size of a machine word; they will always be aligned with memory.
> > Integers are defined this way in the standards.
>
> Let's take a close look at your code. Here is an excerpt from ptr_base:
>
> private:
> element_type * m_ptr;
>
> int & get_count() const
> {
> return * reinterpret_cast<int *>(m_ptr - len<int>() - len<int>());
> }
>
> int & get_type_id() const
> {
> return * reinterpret_cast<int *>(m_ptr - len<int>());
> }
>
> Now, there appear to be numerous problems with this code. First,
> let's look at:
>
> m_ptr - len<int>()
>
> Suppose that sizeof(int) == 4, sizeof(element_type) == 5, and that
> m_ptr % 4 == 1, due to this size. That would make the offset -20,
> but the alignment would not be correct for int!

Since the memory block is aligned, substracting an integer from it will
still result a an aligned memory reference:
        int counter
        int type_id
-> T element_type (aligned)

        int counter
-> int type_id (aligned - len<int>() = aligned)
        T element_type

> Furthermore, this code assumes that
>
> static int s_id;
>
> or
>
> struct __ptr_ctti
> {
> static int s_size;
> };
>
> is located at (char*)m_ptr - 4. But both of those objects are static,
which
> means you should only get one instance per class.

Yes exactly... but s_size is copied into type_id of the allocated memory
block.

> But if your program
> contains more than one ptr_base<>, why on earth would we expect a
> copy of a static object to exist in every instance?? This is very
> confusing!

ptr_ctti::s_size is incremented each time a ptr_base<T>::s_id is
instanciated. This instanciation will be done once for each ptr<T> needed
because it is a static object and this is exactly what I am looking for: a
unique id for each ptr<T>.

> Let's take a look at your conversion/copy c'tor:
>
> template <typename _U>
> __ptr_base(_U * a_p = 0) : m_ptr(reinterpret_cast<_T *>(a_p))
> {
> s_rectify.reserve(__ptr_base<_U, __false_type>::s_id + 1);
> s_rectify[__ptr_base<_U, __false_type>::s_id] = int(static_cast<_T
> *>((_U *) 1) - offset(1));
>
> get_count() = 1;
> get_type_id() = __ptr_base<_U, __false_type>::s_id;
> }
>
> I notice that you try your hardest to stick to C++-style casts, except in
> the
> peculiar construction:
>
> int(static_cast<_T *>((_U *) 1) - offset(1));
>
> Here you cast the constant value 1 to a U*. Very creative. Then you
> subtract
> one byte? And cast back to a T*? What on earth is this code supposed to
> be doing?!?

I won't call (U *) 1 a cast because it is the only official way we can
construct a U pointer without a typedef. This code is writting down the new
pointer static_cast<> will return with the new type. '1' is needed to start
with because '0' is defined as a official NULL value and static_cast<T *>(0)
will always return 0.

> Let's look at the one place it is called, and see if we can
> bring
> any sanity to this code.
>
> element_type * get() const
> {
> return m_ptr + s_rectify[get_type_id()];
> }
>
> Suppose that sizeof(T) = 4 and sizeof(U) = 6. That means our offset is
> computed as 5? Well, first of all, we have a problem.

s_rectify will contain the result of the previous static_cast<T *>((U *)
1) - 1. It is not related to sizeof()s but the location the cast will lead
to. The offset will be similar to a 0, 2, 4, 8, ...

> Conversions
> between pointers are only defined when the conversion results in a
> properly aligned pointer. In this case, it looks like we end up with:
>
> static_cast<T*>(5)
>
> which, with any luck, wouldn't compile, because, among other reasons,
> "5" is not a suitable alignment for T. However, that is not the end of
> our worries. Suppose rectify returned 5 anyway, and we tried to get
> the element_type*. It looks to me that m_ptr is already what we want,
> but what do I know? Instead, we return m_ptr + 5. What is that supposed
> to point to? I have no idea.
>
> You say that this pointer is supposed to be faster than shared_ptr<>.
> But your get() implementation, which is called by operator* (which I
> assume is a fairly frequent operation), contains at least two adds
> and two dereferences more than shared_ptr<>. In fact, you couldn't
> possibly get any faster than shared_ptr<>::operator*. Also,
> shared_ptr<>'s copy c'tor appears to have much less overhead than
> your pointer. I'm really having a hard time seeing where the speed
> difference is, and the direction of that difference.

I mention this before, but get() will result in 1 operator [] () call plus 1
operator + () call only. shared_ptr<> may have a faster get() but let's not
forget ptr<> is slower only with types depending on virtual tables; it is as
fast when you use simple types like ptr<int>.

sort()ing a container with shared_ptr<> is not faster in the end because the
copy constructor of ptr<> requires less CPU cycles (and memory) since
there's only one T * to copy. Not to mention the allocation & deallocation
time required by shared_ptr<> is doubled.

> This line also bothers me:
>
> get_type_id() = __ptr_base<_U, __false_type>::s_id;
>
> It's one thing to poke around where you don't belong, but here you
> brazenly assign to whatever random address is returned by
> get_type_id(). Have you tried compiling this code on a few different
> compilers? Have you tried making some test cases that make sure
> this code really works properly? The test code you uploaded does
> not inspire a lot of confidence.

get_type_id() will return the type_id as a left value. I haven't tried it
on different machine or compilers (I would like to on a SPARC Station with
SGI's compiler) but I can't right now. One thing I'm saying to myself is
that Intel instructions are not well optimized with gcc so it's a good
'worse case scenario'.

Philippe A. Bouchard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk