RAII pointers

Stanislav Blinov via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon May 29 17:32:07 PDT 2017


On Monday, 29 May 2017 at 23:39:17 UTC, Russel Winder wrote:
> C++ allows one to create types that are pointer types but wrap 
> a primitive pointer to give RAII handling of resources. For 
> example:
>
>
>     class Dvb::FrontendParameters_Ptr {
>     private:
>     	    dvb_v5_fe_parms * ptr;
>     public:
>     	    FrontendParameters_Ptr(FrontendId const & fei, 
> unsigned int const verbose = 0, unsigned int const legacy = 0);
>     	    FrontendParameters_Ptr(FrontendParameters_Ptr const &) 
> = delete;
>     	    FrontendParameters_Ptr & 
> operator=(FrontendParameters_Ptr const &) = delete;
>     	    ~FrontendParameters_Ptr() {dvb_fe_close(ptr); }
>     	    dvb_v5_fe_parms * c_ptr() const { return ptr; }
>     	    dvb_v5_fe_parms * operator->() const { return ptr; }
>     };
>
>
> Has anyone any experience of doing the analogous thing 
> idiomatically in D.
>
> I just re-realised I manually constructed a C++ abstraction 
> layer around some of libdvbv5, so I am going to do the same for 
> D. However whilst I (sort of) understand doing the wrapping 
> with C++, I am not sure I have seen anyone wrapping C pointers 
> with RAII in D.

I've found this pattern works rather well:

module frontendparametersptr;

struct FrontendParametersPtr
{
     // No constructors, initialization with parameters
     // is done via the frontendParametersPtr function
     @disable this(this);

     ~this()
     {
         // null check is often useful to detect e.g.
         // if this object has been `move`d
         if (_ptr) dvb_fe_close(_ptr);
     }

     // with DIP1000, could also return `scope`
     inout(dvb_v5_fe_parms)* ptr() inout { return _ptr; }
     alias ptr this;
package:

     void construct(/*your args here*/) { /*...*/ }

private:
     dvb_v5_fe_parms* _ptr;
}

/// Replaces constructor, i.e. can be called with no arguments for
/// replacing "default" construction of C++
auto frontendParametersPtr(Args...)(auto ref Args args)
{
     import std.functional : forward;
     FrontendParametersPtr result = void;
     result.construct(forward!args);
     return result; // moves result, no copy is made
}

///-----

module app;

import frontendparametersptr;

void main()
{
     auto ptr = frontendParametersPtr(/* your args here */);
}


The main idea is that construction is handled by the `construct` 
function (which could be overloaded), instead of `this(...)` 
constructors: this way client code would either get 
default-initialized (.init) pointers, or those constructed with 
appropriate arguments (even with no arguments, if such is needed).
Disabling copying is obvious.
The rest depends on taste and purpose.


More information about the Digitalmars-d-learn mailing list