Re: Garbage Collection in Objective-C++
Re: Garbage Collection in Objective-C++
- Subject: Re: Garbage Collection in Objective-C++
- From: David Elliott <email@hidden>
- Date: Tue, 5 Feb 2008 23:39:47 -0500
Hi Chris,
On Feb 5, 2008, at 11:09 PM, Chris Hanson wrote:
On Feb 5, 2008, at 6:53 PM, David Elliott wrote:
wxObjcAutoRefFromAlloc<void*> s_foo = [[SomeClass alloc] init];
The idea is that wxObjcAutoRefFromAlloc constructs with an already-
retained object (e.g. one from alloc) and releases on destruction.
Copy construction results in a retain so that's not an issue.
Ignore that class for now though as the implementation of it is
horrible, so don't go looking it up.
Really, I think the main issue with what you're trying to do is
expressed above.
(1) You're assigning an object reference to something that's typed
(effectively) as "void *" so you're pretty much hiding the object
reference from the collector.
Perhaps I wasn't clear that I changed the code to use id instead of
void* which DID cause the objc_assign_strongCast to be emitted. But
it doesn't work because the compiler is emitting the
wxObjcAutoRefFromAlloc constructor sort of like this:
wxObjcAutoRefFromAlloc(T ptr)
{
objc_assign_strongCast(ptr, &m_ptr);
}
This appears to work fine so long as the wxObjcAutoRefFromAlloc object
is allocated on the heap. If it is allocated in the global data area
then the strongCast is completely ignored. The compiler can of course
not know this information when generating the constructor for
wxObjcAutoRefFromAlloc which is I believe the fundamental problem here.
(2) You're using different memory management semantics than normal,
by expecting the initial -retain sent to the object reference to
come from "outside" the object you're passing it to.
No, I'm using memory management semantics appropriate for C++ pointer-
holders. See below.
You can change #2 so that the above line of code under non-GC would
read like this:
wxObjcAutoRefFromAlloc<void*> s_foo = [[[SomeClass alloc] init]
autorelease];
There is no NSAutoreleasePool during C++ static initialization time so
this is unworkable.
In other words, assigning an object reference *to* one of these
should cause a retain.
I agree with you that your idea more closely follows Objective-C
semantics but it goes completely against C++ pointer-holder semantics.
A much better class to look at in wx is the wxCFRef<refType> that I
wrote years later (i.e. a few months ago instead of a few years ago).
Like the standard library auto_ptr or TR1 shared_ptr it has an
explicit constructor from a pointer which assumes it is taking
ownership of the pointer.
This semantic was at the behest of Stefan Csomor (the wxMac author)
and I decided that he was very right about it. More often than not
you are creating the wxCFRef from a CF Create* method and if you got
it from a Get* method instead then you can simply use the following
pattern:
wxCFRef<CFStringRef>
myString(CFRetain(CFSomethingElseGetSomeString(somethingElse)));
The "gotcha" is that constructing from the raw pointer and that copy-
constructing from another ref have different semantics. However, the
same is true of shared_ptr in exactly the same way and thus from a C++
programmer's point of view the disparity makes perfect sense.
A similar situation occurs in Objective-C. When you are using these C+
+ pointer holders more often than not you are allocating the object
yourself and thus it is already retained. Should you not have a
reference to it you should retain it on the Objective-C side like this:
wxNewStyleObjcRef<NSString*> myString([[SomeControl stringValue]
retain]);
I realize it rightly offends your Objective-C sensibilities but
looking back on it, the wxObjcAutoRef class should never have existed
and the semantics used by wxObjcAutoRefFromAlloc should have been the
only ones available. My mistake in writing the original wxObjcAutoRef/
wxObjcAutoRefFromAlloc was to assume the Objective-C semantics were
appropriate.
Then, once your wxObjcAutoRefFromAlloc<T> class retains on
assignment, you can convert it from sending -retain and -release to
instead call the CFRetain and CFRelease functions. These
effectively add and remove a root under GC, and they will cause -
retain and -release to be sent under non-GC, so you should get
correct behavior in all circumstances.
Ok, now that is an interesting and very workable idea. I did not
realize that it was safe to call CFRetain/CFRelease on all Objective-C
objects. I thought it only applied to those that were explicitly toll-
free bridged. If this is the case then it would seem I'd want to
declare the C++ i-var as weak (thus avoid objc_assign_strongCast from
the compiler) and use explicit CFRetain/CFRelease. Will this work on
older OS X as well or only on more recent versions?
I will probably have to adjust this to [(id)CFRetain(ptr) release]; to
keep my C++ pointer-holder semantics but that should still be workable
as under non-GC mode it boils down to retain/release (e.g. no-op) thus
keeping the ref count at 1 (from the alloc) which will be balanced by
the CFRelease (e.g. regular release) in the destructor. In GC mode it
does a forceful CFRetain and a release no-op which will be balanced by
the CFRelease.
-Dave
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden