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.