J
Jason Heyes
I wrote a previous post that asked whether there was a reference-counted
implementation of std::vector. Apparantly there wasn't. So my next question
is, is it possible to write your own shared container that behaves like
std::vector?
Here is me trying to answer that question:
class FooReference;
// user class
class Foo
{
int a;
public:
Foo() : a(3) { }
int get() const { return a; }
void set(int a_) { a = a_; }
// reference support
Foo(const FooReference &ref) : a(ref.access().a) { }
Foo &operator=(const FooReference &ref) { a = ref.access().a; }
};
// common to all references
template <class T>
class ReferenceBase
{
SharedPtr<std::vector<T> > &cont;
typename std::vector<T>::size_type pos;
protected:
T access() { cont.unshare(); return (*cont)[pos]; }
const T &access() const { return (*cont)[pos]; }
public:
typedef std::vector<T> container_type;
typedef typename container_type::size_type size_type;
ReferenceBase(size_type pos_, SharedPtr<container_type> &cont_) :
pos(pos_), cont(cont_) { }
ReferenceBase &operator=(const ReferenceBase &ref)
{ access() = ref.access(); return *this; }
};
// custom user-made reference
class FooReference : public ReferenceBase<Foo>
{
friend class Foo;
public:
FooReference(ReferenceBase<Foo>::size_type pos,
SharedPtr<ReferenceBase<Foo>::container_type> &cont) :
ReferenceBase<Foo>(pos, cont) { }
// public methods of Foo
void set(int a) { access().set(a); }
int get() const { return access().get(); }
FooReference &operator=(const Foo &rvalue)
{ access() = rvalue; return *this; }
};
// reference for basic types like int,char,etc
template <typename T>
class BasicReference : public ReferenceBase<T>
{
public:
BasicReference(ReferenceBase<T>::size_type pos,
SharedPtr<ReferenceBase<T>::container_type> &cont) :
ReferenceBase<T>(pos, cont) { }
BasicReference &operator=(const T &rvalue)
{ access() = rvalue; return *this; }
friend T &operator=(T &lvalue, const BasicReference &ref)
{ lvalue = ref.access(); return lvalue; }
};
// note the special template parameter
template <class T, class R = BasicReference<T> >
class SharedVector
{
SharedPtr<std::vector<T> > ptr;
public:
// typedefs same as std::vector except for these two
typedef R reference;
typedef const R const_reference;
// public interface same as std::vector, forwarding to ptr
// except for copy constructor, operator= and destructor
// which are compiler-generated ones
// only explicit mutator methods unshare ptr
};
// for convenience
typedef SharedVector<Foo, FooReference> FooVector;
As you can see, my shared container class will return reference objects that
act like normal C++ references (only that operator& is not defined). I have
yet to write an iterator for my shared container because I don't know how to
do it yet. But what do you guys think of what I have done so far? Thanks.
implementation of std::vector. Apparantly there wasn't. So my next question
is, is it possible to write your own shared container that behaves like
std::vector?
Here is me trying to answer that question:
class FooReference;
// user class
class Foo
{
int a;
public:
Foo() : a(3) { }
int get() const { return a; }
void set(int a_) { a = a_; }
// reference support
Foo(const FooReference &ref) : a(ref.access().a) { }
Foo &operator=(const FooReference &ref) { a = ref.access().a; }
};
// common to all references
template <class T>
class ReferenceBase
{
SharedPtr<std::vector<T> > &cont;
typename std::vector<T>::size_type pos;
protected:
T access() { cont.unshare(); return (*cont)[pos]; }
const T &access() const { return (*cont)[pos]; }
public:
typedef std::vector<T> container_type;
typedef typename container_type::size_type size_type;
ReferenceBase(size_type pos_, SharedPtr<container_type> &cont_) :
pos(pos_), cont(cont_) { }
ReferenceBase &operator=(const ReferenceBase &ref)
{ access() = ref.access(); return *this; }
};
// custom user-made reference
class FooReference : public ReferenceBase<Foo>
{
friend class Foo;
public:
FooReference(ReferenceBase<Foo>::size_type pos,
SharedPtr<ReferenceBase<Foo>::container_type> &cont) :
ReferenceBase<Foo>(pos, cont) { }
// public methods of Foo
void set(int a) { access().set(a); }
int get() const { return access().get(); }
FooReference &operator=(const Foo &rvalue)
{ access() = rvalue; return *this; }
};
// reference for basic types like int,char,etc
template <typename T>
class BasicReference : public ReferenceBase<T>
{
public:
BasicReference(ReferenceBase<T>::size_type pos,
SharedPtr<ReferenceBase<T>::container_type> &cont) :
ReferenceBase<T>(pos, cont) { }
BasicReference &operator=(const T &rvalue)
{ access() = rvalue; return *this; }
friend T &operator=(T &lvalue, const BasicReference &ref)
{ lvalue = ref.access(); return lvalue; }
};
// note the special template parameter
template <class T, class R = BasicReference<T> >
class SharedVector
{
SharedPtr<std::vector<T> > ptr;
public:
// typedefs same as std::vector except for these two
typedef R reference;
typedef const R const_reference;
// public interface same as std::vector, forwarding to ptr
// except for copy constructor, operator= and destructor
// which are compiler-generated ones
// only explicit mutator methods unshare ptr
};
// for convenience
typedef SharedVector<Foo, FooReference> FooVector;
As you can see, my shared container class will return reference objects that
act like normal C++ references (only that operator& is not defined). I have
yet to write an iterator for my shared container because I don't know how to
do it yet. But what do you guys think of what I have done so far? Thanks.