Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Resource management

40 views
Skip to first unread message

Norman J. Goldstein

unread,
Oct 24, 2015, 2:33:59 PM10/24/15
to
In this email, I am asking for feedback on resource management.
I give a couple of examples using std::unique_ptr.
The final example is on managing an integer file descriptor.

std::unique_ptr is great for automating the release of resources
when a standard C++ pointer to an object is the target.
More generally, std::unique_ptr takes two template parameters

template <typename _Tp, typename _Dp = default_delete<_Tp> >
class unique_ptr;

so that, for example, to manage an X Display, you can define

template<>
struct default_delete< Display >
{
void operator()( Display* t ) const { XCloseDisplay(t); }
};

and then use

unique_ptr< Display > display( XOpenDisplay( nullptr ) );

to manage the scope of your display resources.
This seems to be a fairly reasonable approach.

Another example is to manage an XDG Handle. You can define

template<>
struct default_delete< xdgHandle >
{
void operator()( xdgHandle* t ) { xdgWipeHandle(t); }
};

and then use

xdgHandle handle;
unique_ptr< xdgHandle > xdgp = xdgInitHandle( &handle );

Here, things are a bit different, as the user needs to instantiate
a handle, before initializing it. However, things do work
properly, if not a bit more awkwardly, with this approach.

The above two examples have a danger, that we are messing with
the deleters of objects that we have do not have full control
of, and could be messing up code elsewhere in the system.

As a final example, to deal with an integer file descriptor,
dispense with unique_ptr, and simply define

struct IntFD {
int fd_;
IntFD( int fd = -1 ) : fd_( fd ) {}

int get( void ) const { return fd_; }

~IntFD(){ ::close( get() ); }
};

and then use

IntFD fd = open( "filename", O_WRONLY );

It would be nice to have a uniform way to manage the scope of resources.
Any suggestions? Have you seen other approaches?
I suspect that families of resources might have uniform ways
of being managed, but, generally, each resource should have its
own management struct, such as IntFD.









Paavo Helde

unread,
Oct 24, 2015, 3:37:44 PM10/24/15
to
"Norman J. Goldstein" <nor...@telus.net> wrote in news:n0giu2$eoe$1
@speranza.aioe.org:
IMO, this is a hack abusing std::unique_ptr as a way to implement RAII
while saving a couple of code lines. This can be used to such effect when
encapsulating pointers, but it will make two concepts (RAII and pointers)
closely intertwined which creates unnecessary strong coupling.

I would much prefer the approach you used in IntFD instead: for each
resource type there should be a dedicated class which owns the resource
and releases it in the destructor. This makes the design more flexible
and avoids unneccesarily tight couplings. One can create the objects of
this class on stack, on heap, owned by unique pointers or shared pointers
as needed, etc.

Cheers
Paavo



Luca Risolia

unread,
Oct 24, 2015, 5:03:20 PM10/24/15
to
Il 24/10/2015 20:33, Norman J. Goldstein ha scritto:
> It would be nice to have a uniform way to manage the scope of resources.
> Any suggestions? Have you seen other approaches?
> I suspect that families of resources might have uniform ways
> of being managed, but, generally, each resource should have its
> own management struct, such as IntFD.

I don't think there can be one uniform way to handle all possible
situations. I tend to avoid to implement wrappers like IntFD whenever
possible. I often use "final action objects" (e.g. made with
BOOST_SCOPE_EXIT) to cleanup resources when there is no ideal resource
handle. For member data in some cases I use scoped pointers (e.g.
unique_ptr<>'s) with custom deleters.

woodb...@gmail.com

unread,
Oct 25, 2015, 6:38:14 PM10/25/15
to
I agree. I use unique_ptr, but not a lot.


Norman J. Goldstein

unread,
Oct 25, 2015, 7:02:36 PM10/25/15
to
As a follow-up to my original post, I want to thank people
for their responses. The consensus seems to be to have a
resource-specific struct for each resource, and
to stay away from abusing unique_ptr. I think an approach like
BOOST_SCOPE_EXIT has its place, but not for the type of
resource management being discussed -- the resource needs to
be allocated, anyway, so just code up the release code in the
destructor, and, then, no program-specific BOOST_SCOPE_EXIT is
needed.

Attached(below) is a no-frills header file with 5 resource managers,
which I have just used and tested in a small program. I am
certain I will be re-using this functionality in future code.
The code needs to be broken into separate header files, maybe
use namespaces, .... Any other suggestions on this? I have
used the "_mgr" suffix for the resource classes, like the "_ptr"
suffix on the smart pointers.

====================
/*
The structs in this file are resource managers. When the object
goes out of scope, the resource is freed. If the struct has the
method get(), possibly const, it should return the resource that
is being managed. The return value can be a value, a refererence or
a pointer, whichever is appropriate for the particualr resource.
*/

PS I was not able to send the header file as an attachment.


//============ Integer file descriptors ===============
#include <unistd.h> // close

// Example:
// IntFD fd = open( "filename", O_WRONLY );
struct IntFD_mgr {
int fd_;
IntFD_mgr( int fd = -1 ) : fd_( fd ) {}

int get( void ) const { return fd_; }

~IntFD_mgr(){ close( get() ); }
};


//============ X resources ===============
#include <X11/Xlib.h>

struct Display_mgr
{
Display* display_;

Display_mgr( Display* disp = nullptr ) :
display_( disp )
{}

Display* get( void ) const { return display_; };

~Display_mgr() { XCloseDisplay( get() ); }
};

struct FontWithDisplay_mgr
{
XFontStruct* fontStruct_;
Display* display_;

FontWithDisplay_mgr( XFontStruct* fs = nullptr,
Display* disp = nullptr ) :
fontStruct_( fs ),
display_( disp )
{}

XFontStruct* get( void ) const { return fontStruct_; };

~FontWithDisplay_mgr() { XFreeFont( display_, get() ); }
};


//============ syslog management ===============
#include <syslog.h>
#include <sstream> // insertion convert to string

// Only one instance allowed per process
struct SystemLogger_mgr
{
SystemLogger_mgr( const char *ident, int option, int facility)
{
openlog( ident, option, facility );
}

~SystemLogger_mgr() { closelog(); }
};

// Allows stream logging such as
// SysLog( LOG_ERR, "value= " << 5 );
#define SysLog( P, D ) \
if( LOG_MASK(P) ) { \
std::stringstream str; str << D; \
syslog(P, str.str().c_str() ); }


//============ XDG management ===============
#include <basedir.h>

// Example:
// XDGHandle xdgh;
struct XDGHandle_mgr {
xdgHandle handle_;

XDGHandle_mgr( void ) { xdgInitHandle( get() ); }

xdgHandle* get( void ) { return &handle_; }

~XDGHandle_mgr(){ xdgWipeHandle( get() ); }
};

Ian Collins

unread,
Oct 25, 2015, 9:13:52 PM10/25/15
to
Norman J. Goldstein wrote:
> As a follow-up to my original post, I want to thank people
> for their responses. The consensus seems to be to have a
> resource-specific struct for each resource, and
> to stay away from abusing unique_ptr. I think an approach like
> BOOST_SCOPE_EXIT has its place, but not for the type of
> resource management being discussed -- the resource needs to
> be allocated, anyway, so just code up the release code in the
> destructor, and, then, no program-specific BOOST_SCOPE_EXIT is
> needed.

That's generally how I do it. Some types of resource may have specific
requirements around copying and sharing.

> Attached(below) is a no-frills header file with 5 resource managers,
> which I have just used and tested in a small program. I am
> certain I will be re-using this functionality in future code.
> The code needs to be broken into separate header files, maybe
> use namespaces, .... Any other suggestions on this? I have
> used the "_mgr" suffix for the resource classes, like the "_ptr"
> suffix on the smart pointers.

I would consider those to be clutter in this context.

> ====================
> /*
> The structs in this file are resource managers. When the object
> goes out of scope, the resource is freed. If the struct has the
> method get(), possibly const, it should return the resource that
> is being managed. The return value can be a value, a refererence or
> a pointer, whichever is appropriate for the particualr resource.
> */
>
> PS I was not able to send the header file as an attachment.

Welcome to Usenet!

> //============ Integer file descriptors ===============
> #include <unistd.h> // close
>
> // Example:
> // IntFD fd = open( "filename", O_WRONLY );
> struct IntFD_mgr {
> int fd_;
> IntFD_mgr( int fd = -1 ) : fd_( fd ) {}

I'm not a big fan of default parameters in constructors, I would have
written

int fd_ {-1};

IntFD() = default;
IntFD( int fd ) : fd_ {fd} {}

> int get( void ) const { return fd_; }

It's better to avoid C's use of void here, get() is idiomatic C++.

I would also add the full set of constructors and assignment operators
with the appropriate = default or = delete to make it clear which ones
are legal for this type of object.

--
Ian Collins
0 new messages