Steven Schveighoffer wrote:

Looks like a good start.

A few things:

1. Proposal point 3, you need to AddRef first, THEN Release the original. Reason being, you could be assigning a reference the same value as before. In this case, if you decrement *first*, you will decrement the reference, which might reduce it to 0, and free the object before you increment. In most cases, the AddRef and Release are elided, so it's not bad if you do this.

I wonder if it's not a good idea to have a RefAssign function that takes two RC objects and does a check to see if they are the same before doing AddRef and Release to help with this issue. Calls where the compiler can prove they are the same value can be elided.

2. AddRef and Release should be treated not as function calls, but as callables. That is, if for some reason AddRef and Release should be aliases, this does not detract from the solution. Only requirement should be that they cannot be UFCS, as that doesn't make any sense (one cannot add reference counting after the fact to an object).

I'm thinking of the Objective-C objects, whose functions are "release" and "retain". It would be good to use the names Objective-C coders are used to.

3. Objective-C ARC uses a mechanism called auto-release pools that help cut down on the release/retain calls. It works like this:

@autoreleasepool {  // create a new pool
     NSString *str = [NSString stringWithFormat:@"an int: %d", 1];
     @autoreleasepool { // create a new pool on the "pool stack"
           NSDate *date = [NSDate date];
           {
               NSDate *date2 = [NSDate date];
           }
     } // auto-release date and date2
} // auto-release str

In this way, it's not the pointer going out of scope that releases the object, it's the release pool going out of scope that releases the object. These release pools themselves are simply RC objects that call release on all their objects (in fact, prior to the @autoreleasepool directive, you had to manually create and destroy these pools).

The benefit of this model is that basically, inside a pool, you can move around auto-released objects at will, pass them into functions, return them from functions, etc, without having to retain or release them for each assignment. It's kind of like a mini-GC.

It works by convention, that any function that returns a RC object:

if it's called 'new...' or 'init...' or 'alloc...' or 'copy...', then the object is assumed returned with it's retain count incremented on behalf of the calling scope. This means, if you assign it to a member variable, for instance, you do not have to retain the object again, and if it goes out of scope, you must call release on it.

All other functions return 'auto-released' objects, or objects which have queued in the latest auto release pool. The compiler knows this and can elide more of the releases and retains.

Would this be a mechanism that's worth putting in? I think it goes really well with something like TempAlloc. I don't think we should use convention, though...

-Steve

Reply via email to