[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]

Strong pointer temporaries



Supressing some details, here's the results.  The first case in main
below works with no problems.  The other three cases (which are
various versions of Dean's scheme) works in a rather dangerous, but
possibly workable way.  

In the first case, there is at any moment at least one strong pointer
to any non-garbage object.  The other three cases all work in an
identical fashion (and even generate the same code): The internal
strong pointer is destructed and the function returns the
corresponding wimpy pointer.  The caller then initializes a temporary
strong pointer with this wimpy pointer.  Note that if a garbage
collect happens after the internal strong pointer is destructed (which
can only happen (given non-pre-emption) as a result of this or other
local destructors), then our garbage collector may garbage collect
non-garbage.  Barring destructor-invoked collection, we are apparently
guaranteed to be holding onto our objects with strong pointers by the
time any code other than local destructors are called.

We do far far too much stuff in our local destructors to have to worry
about being sure not to invoke a garbage collection during procedure
return.  Therefore (if no one objects) I hereby pronounce the first
case in main below valid, and the other three cases invalid by virtue
of violating the wimpiness constraint: "It is ok to wimpily point ONLY
at objects which you know be non-garbage because of strong pointers.".
Admittedly it is a subtle point that the first case below doesn't
violate this and the others do, but them's the breaks.

For many of the same reasons, case 1 below will work with ref-count
collection, but the other three break, as the object's count will go
from 1 to 0 to 1 during the function return.  A refcount collector
will collect it when it goes to 0.  For the first case, the refcount
will go from 1 to 2 to 1, and all will be well.

One more plug for 2.0: These kinds of examples stretch the language
and compiler into some strange corners.  Although I ran into some
complaints from the compiler about unimplemented features, I ran into
no compiler bugs.  My confidence in being able to do this kind of
thing and have it work in 1.2 would have been rather low.


Abbreviated code:


class FooPtr {
  public:
    Foo * operator-> () CONST;
    Foo& operator* () CONST;
    Foo& operator= (CONST FooPtr& other);
    operator Foo * () CONST;
    FooPtr (Foo * p = NULL);
    FooPtr (CONST FooPtr& other);
    ~FooPtr ();
  private:
    int ptrCount;
    Foo * ptr;
};


void f1 (FooPtr x, FooPtr y)
{
    FooPtr z = y;
}

FooPtr g1 ()
{
    FooPtr p = new Foo();
    return p;
}

FooPtr h1 ()
{
    FooPtr p = new Foo();
    return p;
}



Foo * g2 ()
{
    FooPtr p = new Foo();
    return p;
}

Foo * h2 ()
{
    FooPtr p = new Foo();
    return p;
}


main (int, char *[])
{
    cerr << "test1\n";
    {
	f1 (g1(), h1());
    }
    
    cerr << "\ntest2\n";
    {
	f1 (g2(), h2());
    }
    
    cerr << "\ntest3\n";
    {
	f1 (FooPtr (g2()), FooPtr (h2()));
    }
    
    cerr << "\ntest4\n";
    {
	f1 ( (FooPtr) g2(), (FooPtr) h2());
    }
}