|
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