Memory management of C libraries in C++

Posted on November 6, 2014 by Kevin.

Today I had some time to play around with libgit2, an excellent C-library for Git. But since I was thinking about using it together with the freshly released Proxygen, the fast HTTP-framework from Facebook, I wanted to use the library functions from C++ from the start.

This was a perfect opportunity to play around with C++ memory management objects in the context of a C-library.

Academic Example

In C-libraries, one often finds the following pattern for construction and destruction of objects on the heap:

typedef struct { /*...*/ } object_t; object_t *object_new(); void object_free(object_t *);

The important thing here is that object_new() returns an owning pointer and it is the user’s responsibility to clean up after use. If the user forgets to call object_free , the memory is leaked.

With std::unique_ptr and std::shared_ptr , C++ offers smart containers for memory management which guarantee that the memory is freed after use. They also allow the user to specify a custom “deleter” which is particularly helpful when dealing with C-library functions.

using uniqueObjectPtr = std::unique_ptr<object_t, decltype (&object_free)>; uniqueObjectPtr obj{object_new(), object_free};

A working example of this can be found in kdungs/cpp-neat/ManageC.

Real World Example: libgit2

Take for example the following snippet that makes use of libgit2 to load information about a local git repository

git_repository *repo = NULL; git_repository_open(&repo, "./testrepo" ); /* Do something with repo. */ git_repository_free(repo);

In a C++-context, we don’t want to take care of manually freeing the memory. Instead, we put the resulting repo into a memory managing object, that knows which function to call in order to free the memory.

using uniqueRepositoryPtr = std::unique_ptr<git_repository, decltype (&git_repository_free)>; git_repository *rawRepo = nullptr ; git_repository_open(&rawRepo, "./testrepo" ); uniqueRepositoryPtr repo{std::move(rawRepo), git_repository_free};

I agree that it is a bit clumsy to first declare a raw pointer that is then moved into the memory managing object. The problem here is that libgit2 uses the return value of most of its functions for error codes and I don’t see a way around that.