Main Page | Namespace List | Class Hierarchy | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages

Functional use

Construct a DynObj from a variety of sources

You may want to create:

The DAO or type of auto_ptr or DynTmp can be different from that of DynObj, the compiler will check that the conversion is legal. I.e.

    class Foo {};
    class Derived: public Foo {};
    class Bad {};
    DynObj<Derived> der;
    RRef<Foo> foo(der); // legal
    RRef<Bad> foo2(der); // illegal, compile error

Construct an RRef from a variety of sources

You may want to create:

Change the DAO represented by a DynObj

You may want a DynObj to represent a different DAO. This is done by one of the acquire() methods. Provide the overloaded versions of acquire() as for the DynObj constructor.

Change the object represented by an RRef

You may want a RRef to represent a different object. This is done by one of the reset(C) methods, which each have an operator=(C) counterpart and an RRef(C) constructor counterpart.

Reset a DynObj or RRef to a default state

You may want to reset a DynObj or RRef to represent nothing, as though it had just been default construted. This is done with the reset() method (takes no argument).

Make DynObj release a DAO from management

You may want a DynObj to stop representing a DAO without destroying it, i.e. you take control of the destruction of the DAO. This would likely happen if you had to give control of the lifetime of the DAO to a third-party library or legacy code.

Swap two DynObjs or two RRefs

DynObj can't be copied so the default std::swap does not work with DynObj. A method called swap() is provided instead. As to RRef, a swap method is not necessary since RRefs can be shallow copied, but is provided for consistency.

Give access to DAO inside DynObj and RRef

The DynObj and RRef proxies should give access to the DAO via a function, or member function or operator. Want something short and easy to type. Options were:

Therefore, use operator() to get a reference to the object stored in DynObj or RRef, and chain with a member function or data if needed:

    DynObj<Foo> foo( new Foo ); 
    foo().method();
    foo() = 2; // calls Foo::operator=(int)

Assert before access DAO

Many times you "know" that a DynObj or RRef is not null, but in non-release build of your code this should be asserted "just in case". Yet it is easy to forget this assertion, so make it automatic in the call to operator() of both DynObj and RRef. I.e. if you forget that a DynObj or RRef is null before making a (illegal) call on its operator(), an assertion will fail, something like:

    DynObj<Foo> dynObj; // create null DynObj
    dynObj().method(); // assertion fails
assertion "NoPtr::isNotNull(_obj)" failed at line 300 of file DynObj.hh.

Allow you to get pointer to object in RRef or DynObj

You may need to give address of object stored in RRef or DynObj to legacy code, third party library, etc. This could be done by using & (dynObj()) assuming a DynObj called dynObj. However, you may not want the assertion, but just the address, so have an extra method that directly returns a pointer to the object stored in RRef or DynObj.
    RRef<Foo> foo(dynObj);// assume dynObj exists somewhere
    legacyFunc(foo.getPtr()); // don't check nulless of pointer
    legacyFunc(& foo()); // assert non-nulless of pointer (debug only)

Test nullness of DynObj and RRef

Since operator() returns a reference, you need a way to test that an object is indeed contained. You could use getPtr() == NULL, but it is more expressive to use the isNull() or isNotNull() member functions or free functions:
    if (dynObj.isNotNull()) dynObj().method();
    if (isNotNull(dynObj))  dynObj().method(); // same 

Provide usual comparison operators for objects

You may need to test if two DynObj are different, equal, or ordered, and similarly for RRef. This comparison uses the operators defined on the objects represented, rather than the pointers to the objects, since DynObj and RRef represent the objects they hold rather than pointers. Thus are provided operator==, operator!= and operator< for both DynObj and RRef, independent of the Context template parameter (see the STL uses for what the Context is).

Support polymorphism

Allow the DAO stored to be of a subclass of the class stored. E.g. DynObj<T> and RRef<T> can be given an object of type Derived_of_T:
    class Base {...}; 
    class Derived: public Base {}; 
    DynObj<Base> baseObj( new Derived ); // ok
    RRef<Base> refObj(baseObj); // ok

In this case, make sure, as with raw pointers, that your Base class has a virtual destructor. A special deleter that "remembers" the true type of the DAO stored is not supported since the language does not support it for normal polymorphic use. Supporting this could favor serious bugs if your class doesn't define a virtual destructor just because you know NoPtr doesn't require one, and you end up using your class outside of NoPtr, say in another application.

Hide your implementation

Support pimpl idiom. I.e., allow DynObj and RRef to be data members of a class without the full class definition of their template parameter. This is one use of DAO's and references that is very common. E.g.
    // Foo.hh
    class Bar; // forward decl. sufficient
    class Foo {
        void method();
        DynObj<Bar> bar;
    };

    // Foo.cc
    #include "Bar.hh" // full defn needed here
    void method() {
        // do something with bar
    }

Minimal namespace pollution

"using namespace NoPtr;" brings only user interface into global namespace. Anything that you don't directly need is put in a separate namespace (currently NoPtr::NoPtrImpl).

Note never put a "using" declaration in a header file.

Constness of proxy vs of object contained

You can express the constness of the object stored by DynObj or RRef independently from the constness of the DynObj or RRef, so that they can be made to store a different object if required. Using DynObj as an example:

Receive const obj

You can give an Owned<T*> or RRef<T> to a function that expects a link to a const T, as long as the Owned/RRef is passed by const reference":
    void function1(const DynObj<const Base>&);
    void function2(      DynObj<const Base>&);
    void function3(const RRef<const Base>&);
    void function4(      RRef<const Base>&);
    DynObj<Base> base;
    function1(base); // ok
    function2(base); // compile error
    function3(base); // ok, will create temp rref
    function4(base); // compile error

Converting to a non-const DynObj or RRef is disallowed to enforce const correctness (just think about a bit it and you'll see why).

Compare two proxies

Comparing two DynObj or RRef objects does the comparison on the objects represented. This makes sense since neither are smart pointers, for which the comparison typically compares the raw pointers. Support for nullness must be intuitive:

Transfer DAO

Transfer of ownership must be allowed. Provide an acquire() method when one DynObj takes possession of a DAO owned by another DynObj, and a giveAway() method when one DynObj wants to give away the the DAO it was representing. In the latter case, the DAO must be destroyed if no one is there to "take it over". Therefore, the giveAway() returns a DynTmp rather than a pointer to the DAO.
    DynObj<T> dynObj1(new T);
    DynObj<T> dynObj2(dynObj1.giveAway()); // 1 abandons to 2
    DynObj<T> dynObj3;
    dynObj3.acquire(dynObj2); // 3 takes from 2

Next usage pages:


Generated on Mon Aug 4 18:51:33 2003 for NoPtr C++ Library by doxygen 1.3.2