I have a library implemented in C++ which has a C interface. This C interface is, for all intents and purposes, the only way to use this library. C++11 seems to discourage the use of raw pointers but neither shared_ptr or unique_ptr are suitable in this case. From what I understand, intrusive_ptr is an option, but I am both unsure of how this differs from maintaining my own ref count (I am new to C++) and wary of wading into boost yet (I am new to C++).
How should I handle memory management in C++11 and higher? I only state the spec to make it clear that I am willing to use the features of the latest spec and have no need to maintain compatibility with older specs.
2 Answers 2
The fact that C++11 offers a range of smart-pointer classes to make life easier with memory management does not mean that you can't or shouldn't use raw pointers where that is appropriate.
The committee that maintains the C++ standard is very reluctant to remove existing features from the language and more so if it is a widely used and useful feature like raw pointers. Keeping the language backwards compatible is one of the corner stones in its evolution.
With that said, if you have to provide a C-compatible interface to your C++ library, you should use only features from the common subset of C and C++ in your interface and that means using raw pointers where they are visible in the interface and effectively letting the user of your library deal with allocation/deallocation (although you can provide functions for that).
-
If the library keeps ownership of a resource it would be fine to use smart pointers internally within the library and return raw pointers in the interface, no?Chris Drew– Chris Drew2014年04月19日 07:46:52 +00:00Commented Apr 19, 2014 at 7:46
-
2@ChrisDrew: You are correct. The trickiness arise when these raw pointers are jointly owned (shared) by both the C caller and some other C++ objects in the library.rwong– rwong2014年04月19日 08:06:27 +00:00Commented Apr 19, 2014 at 8:06
-
@rwong, Yes, or if you want to safely transfer ownership from client to library, or vice versa.Chris Drew– Chris Drew2014年04月19日 08:10:14 +00:00Commented Apr 19, 2014 at 8:10
-
@ChrisDrew: Yes, you can use smart-pointers internally. You just have to be very aware that when such a pointer crosses the interface, you are giving out an untracked reference. You must double check that the smart pointer doesn't clean up the resource too early.Bart van Ingen Schenau– Bart van Ingen Schenau2014年04月19日 14:30:25 +00:00Commented Apr 19, 2014 at 14:30
Analysis.
It has to use some kind of intrusive pointer (specifically user-implemented reference counting), though it could be Boost intrusive_ptr
or some other flavor.
My personal opinion.
I have used Microsoft COM pointers in my projects and it works fine. If your code only has to work on Microsoft Windows, this may be the recommended route as the C systems programmer for Windows will probably be familiar with it. For all other considerations, including cross-platform applications, use Boost intrusive_ptr
.
I have described my opinions about the minimal usage of Microsoft COM pointers in this answer.
The nature of intrusive_ptr.
It is important to understand the nature of intrusive_ptr
. It is a handle class, implemented using C++ template. It is provided so that such objects can be owned by C++ callers.
C code cannot see this handle class from their header includes, let along call its methods. Instead, the C code would be calling some extern "C"
methods. This means you will be providing extern "C"
methods which in turn call the intrusive_ptr_add_ref
and intrusive_ptr_release
methods provided by Boost intrusive_ptr
.
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/intrusive_ptr.html
What this means.
Calling C++ methods on this object from C code will require one wrapper function per class method, such as this.
For objects that require add_ref
and release
management, you will provide extern "C"
wrapper functions for those as well.
It is your responsibility to document in an obvious way, or convey to the C programmer, what pointer types in your object are reference-counted. A combination of naming convention, API documentation, API usage sample, and verbal warning is recommended.
Finally, understand the laws (object ownership rules) that needs to be obeyed when using reference counting. See this question and the answer.
Advanced topics - object or interface type cast, interface query, interface segregation
I have only used these techniques with Microsoft COM (via its QueryInterface
method), so I cannot comment on whether one could use these techniques on Boost intrusive_ptr
when programming via an extern "C"
interface.
shared_ptr<T>
alike, which would have been opaque to the C code. How do you decipher an opaque address from a debugger?