[LLVMdev] New type of smart pointer for LLVM

Anton Yartsev anton.yartsev at gmail.com
Wed Oct 1 15:14:04 PDT 2014


Ping!

Suggested is a wrapper over a raw pointer that is intended for freeing 
wrapped memory at the end of wrappers lifetime if ownership of a raw 
pointer was not taken away during the lifetime of the wrapper.
The main difference from unique_ptr is an ability to access the wrapped 
pointer after the ownership is transferred.
To make the ownership clearer the wrapper is designed for local-scope 
usage only.

The main goal of the wrapper is to eliminate leaks like those in 
TGParser.cpp -r215176 
<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.cpp?r1=215176&r2=215175&pathrev=215176&diff_format=f>. 
With the wrapper the fixes applied at r215176 
<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.cpp?r1=215176&r2=215175&pathrev=215176&diff_format=f> 
could be refactored in the more easy and safe way.

Attached is a proposed interface/implementation.
Any ideas, suggestions? Is it OK to move forward with the solution?

> Hello everyone,
>
> I bring to discussion the necessity/design of a new type of smart 
> pointer. r215176 and r217791 rise the problem, D5443 
> <http://reviews.llvm.org/D5443> is devoted to the solution.
> r215176 applies several temporary ugly fixes of memory leaks in 
> TGParser.cpp which would be great to be refactored using smart 
> pointers. D5443 <http://reviews.llvm.org/D5443> demonstrates how the 
> solution with a certain type of smart pointer would look like (see 
> changes in TGParser::ParseDef(), TGParser::InstantiateMulticlassDef() 
> and TGParser::ParseSimpleValue()).
>
> Briefly:
> consider a leaky example:
> {
>   T* p = new T;
>   if (condition1) {
>     f(p); // takes ownership of p
>   }
>   p->SomeMethod();
>
>   if (condition2) {
>     return nullptr; // Leak!
>   }
>
>   g(p); // don't take ownership of p
>   return p;
> }
>
> The preferred solution would look like:
> {
>   smart_ptr<T> p(new T);
>   if (condition1) {
>     f(p.StopOwn()); // takes ownership of p
>   }
>   p->SomeMethod();
>
>   if (condition2) {
>     return nullptr; //
>   }
>
>   g(p.Get());  // don't take ownership of p
>   return p.StopOwn();
> }
>
> Neither unique_ptr nor shared_ptr can be used in the place of 
> smart_ptr as unique_ptr sets the raw pointer to nullptr after 
> release() (StopOwn() in the example above) whereas shared_ptr is 
> unable to release.
>
> Attached is a scratch that illustrates how the minimal 
> API/implementation of a desired smart pointer sufficient for 
> refactoring would look like. Any ideas and suggestions are appreciated.
>
> -- 
> Anton


-- 
Anton

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20141002/a4a5bd1c/attachment.html>
-------------- next part --------------
//===-- CondOwnershipPtr.h - Smart ptr with conditional release -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===//

#ifndef LLVM_ADT_CONDOWNERSHIPPTR_H
#define LLVM_ADT_CONDOWNERSHIPPTR_H

#include <memory>

namespace llvm {

template<class T> 
class CondOwnershipPtr {
  T* Ptr;
  bool Own;

  void Delete() {
    if (Ptr && Own)
      delete Ptr;
  }

  CondOwnershipPtr(const CondOwnershipPtr&); // Prevent from misuse.
  CondOwnershipPtr& operator=(const CondOwnershipPtr&); // Prevent from misuse.

public:
  CondOwnershipPtr() : Ptr(nullptr), Own(false) {}
  explicit CondOwnershipPtr(T* p) : Ptr(p) { Own = Ptr && true; }

  ~CondOwnershipPtr() {
    Delete();
  }

  T* Get() const {
    return Ptr;
  }

  T* StopOwn() const {
    Own = false;
    return Ptr;
  }

  typename std::unique_ptr<T> MakeUnique() {
    assert((!Ptr || Own) && "Ownership was transferred.");
    return std::unique_ptr<T>(StopOwn());
  }

  void Reset(T* P = nullptr) {
    if (P != Ptr) {
      Delete();
      Ptr = P;
      Own = Ptr && true;
    }
  }

  bool Owns() const {
    return Ptr && Own;
  }

  operator bool() const {
    return Ptr != nullptr;
  }

  T& operator*() const {
    return *Ptr;
  }

  T* operator->() const {
    return Ptr;
  }
};

} // end namespace llvm

#endif


More information about the llvm-dev mailing list