Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2003-02-14 15:51:16


I decided that my serial_ptr implemented a variant at the wrong level
of indirection. So now I'm trying out intrusive_ptr with a variant at the
pointee level. This is what my code looks like now:

//-----------------------------------------------------------------------
    class TRecord
    {
    public: // Interface
                        TRecord(void)
                            : ID_(0) { }
                        TRecord(int ID)
                            : ID_(ID) { }
        virtual ~TRecord(void) { }

        void swap(TRecord& Record) { std::swap(ID_,
Record.ID_); }

        int ID(void) const { return ID_; }
    private: // Implementation
        int ID_;
    };

//-----------------------------------------------------------------------
    template <typename T>
    class TCountedRecord
    {
    public: // Interface
                        TCountedRecord(void)
                            : Count_(0) { }
                        TCountedRecord(int ID)
                            : Count_(0) { new (Value_)
TRecord(ID); }
                       ~TCountedRecord(void);

        bool IsRecord(void) const; // No-throw
        unsigned Count(void) const; // No-throw
        int ID(void) const;
                        operator T const&(void) const;
                        operator T&(void);

        T* AddRef(void);
        void Release(void); // No-throw
    private: // Implementation
        typedef boost::detail::lightweight_mutex mutex_type;

        mutable
        mutex_type Mutex_;
        unsigned Count_;
        char Value_[sizeof(T)];
    };

//-----------------------------------------------------------------------
    template <typename T>
    void intrusive_ptr_add_ref(TCountedRecord<T>* p)
    {
        p->AddRef();
    }

//-----------------------------------------------------------------------
    template <typename T>
    void intrusive_ptr_release(TCountedRecord<T>* p)
    {
        p->Release();
    }

This code is still being designed, so I haven't tried it. It might not
work as expected. The idea is that my database records will
derive from TRecord, and my pointers will be intrusive_ptrs to
TCountedRecord<T>.

In case it's not obvious, TCountedRecord is a variant of TRecord
and T. The idea is when I just get record IDs, a TCountedRecord
stores a TRecord with the ID in it. When I get a full record, I use
placement new to install it over the TRecord.

I have several issues, however. First, the variant doesn't support
inheritance hierarchies very well. If I have U derived from T, my
problem is that TCountedRecord<U> isn't derived from
TCountedRecord<T>, and so I can't use dynamic_pointer_cast<>
to cast between my intrusive_ptrs. That's not a problem with
dynamic_pointer_cast<>, of course. The problem is that I can't
store base pointers at all, since the pointers aren't related.

Second, I don't like having to use placement new to construct
my records, but I can't use inheritance, because I don't always
have all the data to construct a full record immediately. So the
variant essentially implements "partial construction". If I could
just have T, rather than variant<TRecord, T>, and only construct
the TRecord sub-object, that would be ideal, but obviously, not
C++.

Another solution is to use a pointer in TCountedRecord instead
of a value. However, that introduces an unnecessary level of
indirection (though I might be forced to resort to that). Another
thing that's not obvious from the interface is that I'm using the
count as the variant tag. A 0 means that a TRecord is present,
and a non-0 means an actual record is present.

Any suggestions on how to deal with polymorphism, or
restructure the design differently are appreciated.

Also, I think Boost could use a value-based variant type.

Dave


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