[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