[LLVMdev] New type of smart pointer for LLVM
Ben Pope
benpope81 at gmail.com
Thu Sep 25 12:44:38 PDT 2014
On Friday, September 26, 2014 02:30 AM, David Blaikie wrote:
>
> The use case I have in mind (of which I've seen several in LLVM and
> Clang) looks something more like this:
>
> struct foo {
> unique_ptr<T> u;
> foo(unique_ptr<T> u) : u(std::move(u)) {}
> int stuff();
> unique_ptr<T> take() { return std::move(u); }
> };
>
> int f1(T& t) {
> // I want to do "stuff" to 't' but I don't own it...
>
> // lying through my teeth
> foo f(std::unique_ptr<T>(&t));
>
> // I really hope 'stuff' doesn't throw, because then we'll end up
> with a double delete
> int i = f.stuff();
> f.take().release(); // not really leaking because I lied in the
> first place
> return i;
> }
Right, I see...
> That's one case - check the revision numbers mentioned in the first
> message on this thread for another example that doesn't involve a
> member, just some rather convoluted ownership semantics (some codepaths
> there's a default object to point at, other codepaths there's a newly
> allocated object) it looks something like this:
>
> T *t = nullptr;
> bool Owning = false;
> if (x) {
> t = new T;
> Owning = true;
> } else
> t = &default;
> func(*t);
> if (Owning)
> delete t;
>
> This comes up not infrequently. The code in func doesn't care if it
> owns, it just wants to do something. Now obviously in the code I just
> wrote it could be easily refactored without much duplication:
OK, I've seen this pattern in code I really wish I didn't own. I'm
especially reminded of a case where the ownership of memory in this
example is replaced with ownership of a lock wrapped in a type-erased
accessor that can lock at construction or during access further down the
stack. I feel your pain.
> if (x)
> func(*make_unique<T>());
> else
> func(default);
>
> But it's not always that simple. Maybe it can/should be made that simple
> and we conclude that we don't want/need conditional ownership, but
> that's what this thread is hopefully here to help decide.
>
>
> Let's see what we can do:
>
> {
> auto p = llvm::make_unique<T>();
> if (condition1) {
> f(p); // takes ownership of p
> }
> p->SomeMethod();
>
> if (condition2) {
> return nullptr; // no leak;
> }
>
> g(p.get()); // don't take ownership of p
> return p; // not p.get()!
> }
>
> f(llvm::unique_ptr<T>& p)
> {
> if(!condition2) // I guess
> p = llvm::make_unique<T>(p, null_deleter()); [1]
> }
>
> Clearly the code is a mess as f(llvm::unique_ptr<T>&) needs to know
> condition2, but smart_ptr as described isn't helping anything.
>
> [1] std::unique_ptr doesn't have a type erased deleter, but perhaps
> a unique_ptr with a type erased deleter is actually the right tool
> for the job..
>
>
> Yes, the lack of type erasure is the issue - and then the lack of
> compatibility with existing unique_ptrs (I'd obviously like to be able
> to make a conditional ownership unique_ptr from an unconditional
> ownership unique_ptr&&, for example, and to be able to take
> unconditional ownership if it is owned, etc)
Your examples are enlightening, thanks.
I can see how a paper_over_the_cracks_ptr<> is tempting during a
transitioning period, but I think that's all it can really be, a stop
gap to a better world where the logic and ownership are separated.
Much refactoring is afoot.
Ben
More information about the llvm-dev
mailing list