11

I have written an extensible c++ wrapper around a very hard to use but also very useful c library. The goal is to have the convience of c++ for allocating the object, exposing its properties, deallocating the object, copy semantics etc...

The problem is this: sometimes the c library wants the underlying object (a pointer to the object), and the class destructor should not destroy the underlying memory. While most of the time, the destructor should deallocate the underlying object. I have experimented with setting a bool hasOwnership flag in the class so that the destructor, assignment operator, etc... will know whether or not it should free the underlying memory or not. However, this is cumbersome for the user, and also, sometimes there is no way to know when another process will be using that memory.

Currently, I have it setup where when the assignment comes from a pointer of the same type as the underlying type, then I set the hasOwnership flag. I do the same when the overloaded constructor is called using the pointer from the c library. Yet, this still does not handle the case when the user has created the object and passed it to one of my functions which calls the c_api and the library stores the pointer for later use. If they were to delete their object, then it would no doubt cause a segfault in the c library.

Is there a design pattern that would simplify this process? Maybe some sort of reference counting?

3
  • you seem to not have any thought about the thread safety of these objects... Commented Jan 5, 2013 at 0:36
  • @ratchetfreak All the wrapper does is call the accessor/mutators, ensure good copy semantics, handle memory, copy lists etc... I do not actually directly touch the data. The c-library is thread safe already. Also, my users will only have access to my wrappers synchronously with the system of callbacks and so on. Where necessary, I have locks on reads/writes to any data. Commented Jan 5, 2013 at 3:08
  • 2
    unique_ptr can in most cases already handle this type of resources, so you don't need to implement the resource management yourself. unique_ptr uses the release method to give up ownership of the stored object.
    – Philipp
    Commented Jan 5, 2013 at 3:34

4 Answers 4

5

If the responsibility for cleaning up dynamically allocated stuff shifts between your wrapper class and the C library based on how things get used, you are either dealing with a badly designed C library, or you are trying to do too much in your wrapper class.

In the first case, all you can do is keep track of who is responsible for the cleanup and hope no mistakes are made (either by you or by the maintainers of the C library).

In the second case, you should rethink your wrapper design. Does all the functionality belong together in the same class, or can it be split into multiple classes. Perhaps the C library uses something similar to the Facade design pattern and you should keep a similar structure in your C++ wrapper.

In any case, even if the C library is responsible for cleaning up some stuff, there is nothing wrong with keeping a reference/pointer to that stuff. You just need to remember that you are not responsible for cleaning up what the pointer refers to.

3
  • What if I ensured a clone was made of the underlying object when it is passed to the lib. Then I can free my memory as I please and it wont effect anything. However, then I wont receive changes to the object back in my class. Commented Jan 5, 2013 at 17:52
  • And yes, some very bad practices were used in this lib. For instance: instead of having the user pass a const char* to a function that sets a string in a structure then making a copy to store in the structure, they expect the user to allocate the string on the fly and pass a char* that it just stores without making a copy. That is one of the main reasons I made a wrapper--to ensure that proper copy semantics were followed. Commented Jan 5, 2013 at 17:55
  • @JonathanHenson: Letting the client allocate something and pass ownership/responsibility of it to the library is a common optimisation technique to avoid excess copying and entirely valid for C libraries (as long as it is done consistently). But it indeed means that, when used from C++, the user may need to make additional copies to conform to the interface requirements of the C library. Commented Jan 6, 2013 at 8:31
4

Often you can use a pattern like this:

class C {
public:
  void foo() {
    underlying_foo(handle.get());
  }

  void bar() {
    // transfers ownership
    underlying_bar(handle.release());
  }

  // use default copy/move constructor and assignment operator

private:
  struct deleter {
    void operator()(T* ptr) {
      deleter_fn(ptr);
    }
  };
  std::unique_ptr<T, deleter> handle;
};

By using release you can explicitly transfer ownership. However this is confusing and you should avoid it if at all possible.

Most C libraries have a C++-like object life cycle (object allocation, accessors, destruction) that maps nicely onto the C++ pattern without ownership transfer.

If users need shared ownership, they should use shared_ptr with your classes. Don't try to implement any ownership sharing yourself.


Update: If you want to make the transfer of ownership more explicit, you can use a reference qualifier:

void bar() && { ... }

Then users must call bar on lvalues like this:

C o;
std::move(o).bar();  // transfer of ownership is explicit at call site
6
  • @Phillip, that looks like exactly what I need. I'll try this and get back with you. Commented Jan 5, 2013 at 3:57
  • One question. What exactly IS ownership in this case. Does it mean the privilege to access/modify the object, or just the ability to construct and destruct the object? Commented Jan 5, 2013 at 4:02
  • basically, once I pass the underlying memory to the c-lib, I am not supposed to ever make a free call to the memory. Though, I can and often will have to access the data in the object. Commented Jan 5, 2013 at 4:06
  • 2
    Ownership is the right to destroy the object.
    – DeadMG
    Commented Jan 5, 2013 at 10:52
  • @JonathanHenson: that's an interesting case that's not covered right now in this idiom: once you have released a unique_ptr, it doesn't store the pointer it held any more. Modeling transfer of ownership and at the same time allowing access to disowned resources seems to be quite confusing for users. How do you control when the C library frees the objects it now owns?
    – Philipp
    Commented Jan 5, 2013 at 21:59
0

There is a straightforward answer to your issue, smart pointers. By using a smart pointer to hold the C library's memory and adding a reference when the pointer is also in the library (and dropping the reference when the C library returns) then you will automatically free the memory when the reference count drops to zero (and only then)

3
  • 1
    This does not address the problem, unless I just badly misunderstand smart pointers. The problem is that sometimes, my destructor should clean up the memory, other times the c-library cleans up the memory. These structures have special init, free functions. The library may call free on its own, before the reference count of the smart-pointer hits 0. I need to basically decide ownership and let it go. I don't need a smart pointer to know when to clean up the memory, the problem is that sometimes, I am not the one responsible for cleaning it up and I need to not free it in the destructor--ever. Commented Jan 5, 2013 at 3:10
  • Yep, I agree, I misunderstood the issue. Just one observation, do the different libraries share the same memory allocation table? My intense C/C++ stuff was 10 years ago, and on Visual Studio back then, allocating memory in one library and freeing it in another library would be a memory leak, unless you changed some compiler options for BOTH libraries. Thye consequence of doing this would then be memory management contension on highly threaded applications. Its quite likely this is obsolete info though. Commented Jan 9, 2013 at 22:17
  • not if everything is loaded into the same address space, and it is. Anyways, I am recompiling the c-lib in the same assembly as my wrapper. Commented Jan 9, 2013 at 22:56
0

If the library can free things internally, and the scenarios where this can happen is well documented, then all you can do is set a flag like you're doing already.

1
  • basically, once I pass the underlying memory to the c-lib, I am not supposed to ever make a free call to the memory. Though, I can and often will have to access the data in the object. Commented Jan 5, 2013 at 4:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.