Martin
Martin

Reputation: 9369

Correct idiom for allocating and deallocating resources via C interface

Often C++ programs have to deal with C libraries providing free functions for allocating and freeing a resource. To simplify this example, think about two C functions like get_resource() and free_resource().

Consider an object getting any resource at some point of its life and automatically freeing it once the object is destroyed or not fully constructed because of an error during the construction.

What is an ideal/short/simple idiom for obtaining that automatism? An idea is the following, but it makes the object not properly default-moveable. Is there anything better which does not imply freeing memory from within the destructor or checking errors in the constructor to do rollbacks?

struct Object {
    void* my_get_resource() { // might be called from the constructor or any other point
        return get_resource();
    }

    Object() : up(&resource, &del) { 
        resource = my_get_resource();
        /* init all the stuff, but this init might fail at _many_ points */ 
    }
    //~Object() { if (resource) free_resource(resource); } // I don't like: collides with del and is not called if my_get_resource() is called from the constructor and the init process fails for some reasons

private:
    void *resource = nullptr;
    static void del(void ** ) noexcept {
        if (*resource) { free_resource(resource); }
    }
    unique_ptr < void*, decltype(&del) > up; // RAII: almost good, sadly that makes Object not moveable properly without redefining the move constructor properly


};

Upvotes: 1

Views: 163

Answers (1)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

Apparently you want a RAII wrapper that is movable.

Then just define a move constructor and declare a protected or private copy constructor and copy assignment operator. If you don't plan on supporting current Visual C++, then you can just declare the copy constructor and copy assignment operator as deleted.

This involves checking errors in the constructor and cleaning up in the destructor, which is a odds with your requirements …

Is there anything better which does not imply freeing memory from within the destructor or checking errors in the constructor to do rollbacks?

Simply put, the requirements are generally incompatible with your goal as indicated by the posted code.

Even if you use unique_ptr to do the job, the way it does it is by checking errors in the constructor and cleaning up in the destructor, directly at odds with your (extremely unrealistic) requirements.

Here's how to make a start on doing things "manually":

bool hopefully( bool const c ) { return c; }
bool throwX( string const& s ) { throw std::runtime_error( s ); }

class Resource
{
private:
    void* pResource;

    Resource( Resource const& );    // Add "= delete" if all compilers support it.
    Resource& operator=( Resource const& ); // Ditto.

public:
    void* theValue() const { return pResource; }  // Use problem-specific name.

    ~Resource()
    {
        if( pResource != 0 )
        {
            ::freeResource( pResource );
        }
    }

    Resource()
        : pResource( ::getResource() )
    {
        hopefully( pResource != 0 )
            || throwX( "Resource::<init>: getResource failed" );
    }

    Resource( Resource&& other )
        : pResource( other.pResource )
    {
        other.pResource = 0;
    }
};

You can add a move assignment operator.

And you can generalize the thing to a Handle class template.


Disclaimer: untested off-the-cuff code, not touched by compiler's hands.

Upvotes: 4

Related Questions