This is an archive of the discontinued LLVM Phabricator instance.

ADT: IntrusiveRefCntPtr: Broaden the definition of correct usage of RefCountedBase
ClosedPublic

Authored by dblaikie on Jan 3 2017, 11:38 AM.

Details

Summary

This roughly matches the semantics of std::enable_shared_from_this - that it
does not dictate the ownership model of all users, but constrains those users
taking advantage of the intrusive nature to do so only when there's a guarantee
that that's the ownership model being used for the object being passed.

Diff Detail

Repository
rL LLVM

Event Timeline

dblaikie updated this revision to Diff 82921.Jan 3 2017, 11:38 AM
dblaikie retitled this revision from to ADT: IntrusiveRefCntPtr: Broaden the definition of correct usage of RefCountedBase.
dblaikie updated this object.
dblaikie added a reviewer: jlebar.
dblaikie added a subscriber: llvm-commits.
jlebar requested changes to this revision.Jan 3 2017, 11:43 AM
jlebar edited edge metadata.

I think what I wrote on the mailing list applies here:

btw I don't think it's at all so simple. For example, an object
might, in one of its member functions, cause itself to be
retained/released. This is perfectly valid, but of course will break
you in exciting ways if you allocate the object on the stack.

The advice of "it's safe to allocate these objects on the stack if
you're careful and the object doesn't ever cause itself to be
retained/released" really means "if the object doesn't *currently*
ever cause itself to be retained/released". IOW allocating such an
object on the stack constrains future changes to the object's
implementation. If I had to do a cleanup of code I didn't care about
that was allocating such an object on the stack before I could land a
change I cared about, I'd be pretty annoyed, and rightfully so, I
think.

That is to say, unless it's part of an object's contract that it never
causes itself to be retained/released, I think you're in for a bad
time. Indeed, the same applies for every function you pass that
object to: Unless it is part of that function's contract that it never
causes the object to be retained or released, passing a
stack-allocated object to such a function is going to constrain future
changes to the implementation of that function and all transitive
callees.

This seems like an extremely unfriendly thing to do.

That is, as written this comment seems to say that it's OK for me to take a
class that inherits from RefCountedBase and allocate it on the stack if I am
careful about it. But doing so constrains the author of the class from ever
calling Retain/Release on itself. I think our default should be that this is
allowed, which implies that our default should be that allocating such objects
on the stack is disallowed.

If a class explicitly promises never to Retain/Release itself, then allocating
it on the stack is fine. However, for the same reason, you should only pass it
to functions that promise never to Retain/Release the object.

I'm fine if you want to write this up in a comment, although I am curious what
problem you're trying to solve.

This revision now requires changes to proceed.Jan 3 2017, 11:43 AM
dblaikie updated this revision to Diff 82952.Jan 3 2017, 2:32 PM
dblaikie edited edge metadata.

Remove the contentious comment entirely rather than trying to rephrase it.

jlebar accepted this revision.Jan 3 2017, 2:33 PM
jlebar edited edge metadata.

It also appears in the example above; you may want to get rid of it there too.

This revision is now accepted and ready to land.Jan 3 2017, 2:33 PM
This revision was automatically updated to reflect the committed changes.