LFC development is intended to be an open process which should benefit from the best ideas and experience from all of the team members. Request For Comments (RFC) are descriptions of new ideas and proposals and they are intended to:
Each new concrete idea/proposal that will affect LFC should be described in a
RFC. There can be multiple incremental versions of an RFC before a final solution is
proposed for approval. An RFC could describe not only technical solutions, but ideas
for project organization, LFC marketing, ...
An RFC should contain:
****
Notes:
Name LFC2 Smart Pointers (rev2)
Description
Smart pointers are objects that (try to) behave like build-in C++ pointers (aka
dumb pointers) adding extra functionality.
As you know, pointers are extremely important in C++, but working with pointers
and dynamically allocated objects has some serious drawbacks:
I propose here a design of a reference-counting smart pointer variant that try to address the problems above, offering:
****
Requirements
****
Known limitations
****
Some usage examples
// smart pointer declarations
Ptr<Base> sp1; // null initialized
Ptr<Deriv> sp2(new Deriv); // point to new Base object
Ptr<Base> sp3(sp2); // init form another smart ptr (note Deriv ->
Base conversion)
//Ptr<Base> sp4 = new Base; // fail: Ptr<T>(T*) is explicit
Ptr<Deriv> sp4 = lfcNull; // init to NULL (useful for func args)
Ptr<const Base> sp5 = sp3; // Ptr to const object (note non-const
-> const conversion)
Ptr<double> sp6; // Ptr to a build-in type
// basic usage
sp2->f();
sp2->x = 10;
Deriv obj = *sp2;
//sp1->f(); // will throw an exception (null dereferencing)
//*sp1; // idem
// copying and conversions
// (similar to build-in pointers, if T1* -> T2* then Ptr<T1> ->
Ptr<T2>)
sp1 = sp2; // ok, Ptr<Deriv> -> Ptr<Base>
//sp2 = sp3; // fail, Ptr<Base> -> Ptr<Deriv> is illegal
sp2 = sp2.dynamicCast<Deriv>(); // ok, dynamic cast (may return a
null ptr)
// comparations (2 smart ptr are equal if they point to the same
object)
sp1 == sp2; // false
sp1 == sp3; // true
sp1 == lfcNull; // true
lfcNull == sp1; // true
sp1.isNull(); // true
// special usage
Base *p = sp2.realPointer(); // use with caution!
// now, all unreferenced objects
// will be automaticaly deleted
My proposed solution (Ptr<T>)
//! Ptr<T> represent a smart pointer to a T object
template<class T>
class Ptr : private PtrBase
{
public:
.... explicit Ptr(T *p = NULL) throw();
.... Ptr(const Ptr &ptr) throw();
.... Ptr(Null) throw();
.... ~Ptr() throw();
.... template<class X>
.... Ptr(const Ptr<X> &ptr) throw();
public:
.... const Ptr &operator=(const Ptr &ptr) throw();
.... template<class X>
.... const Ptr &operator=(const Ptr<X> &ptr) throw();
.... const Ptr &operator=(T *p) throw();
.... template<class X>
.... const Ptr<X> dynamicCast() const;
.... bool isNull() const throw();
.... T *operator->() const;
.... T &operator*() const;
.... T *realPointer() const;
};
template<class T1, class T2>
inline bool operator==(const Ptr<T1> &p1, const Ptr<T2> &p2) throw();
template<class T>
inline bool operator==(const Ptr<T> &ptr, Null) throw();
template<class T>
inline bool operator==(Null, const Ptr<T> &ptr) throw();
I would appreciate any comments (especially regarding the thread-safe issue).
Lemo.