15

I'm looking for a good resource for learning about good API design for C++ libraries, looking at shared objects/dlls etc. There are many resources on writing nice APIs, nice classes, templates and so on at source level, but barely anything about putting things together in shared libs and executables. Books like Large-Scale C++ Software Design by John Lakos are interesting but massively outdated.

What I'm looking for is advice i.e. on handling templates. With templates in my API I often end up with library code in my executable (or other library) so if I fix a bug in there I can't simply roll out the new library but have to recompile and redistribute all clients of that code. (and yes, I know some solutions like trying to instantiate at least the most common versions inside the library etc.)

I'm also looking for other caveats and things to mind for keeping binary compatibility while working on C++ libraries.

Is there a good website or book on such things?

johannes
  • 3,601
  • 2
  • 26
  • 32
  • I handled it this way: http://sivut.koti.soon.fi/~terop/GameApi.html -- i.e. while there are templates inside the lib, none of it is in the api... – tp1 Sep 02 '12 at 14:36
  • DeadMG: Well, that's the kind of quality you can get if you work hard for few years. Once you have better example, please tell us where it is. While you'll think it's not good quality, my claim is just that making better one takes more effort than you'd think. – tp1 Sep 02 '12 at 15:43
  • It's the kind of quality where you take a terrible C API, make it a bunch worse (you don't even use opaque pointers but a terrible "I made an int and pretended it was a pointer" thing), and then add a couple member functions and call it C++. Your API is so bad, I couldn't even work out what half of it was *supposed to do* to write an example replacement. Well, I wrote a better example in my free time, which you can find in my bitbucket repo. [this](http://pastebin.com/JXGcS5C6) is just the beginning of how it might begin to resemble actual C++. – DeadMG Sep 02 '12 at 16:00
  • @deadmg: Your example is the old stuff. (already been there, and it's not suitable for api) – tp1 Sep 02 '12 at 16:03
  • 1
    `std::unique_ptr` is pretty new stuff. What exactly did you think was *more* suitable about your proposed API? The way in which you had to manually manage all the resources, virtually guaranteeing leaks and double deletes, for example? Or the way in which many of your types had one or two letter names, making divining their purpose impossible? – DeadMG Sep 02 '12 at 16:09
  • deadmg: but you didn't notice that when you add new function to your "api", you lose binary compability. (or that the alternative I have do not have any memory-related problems in it) – tp1 Sep 02 '12 at 16:12
  • @tp1: That only happens if you're a moron. More to the point, I mean, gosh, how could it be that changing the API, not just it's implementation, could be a breaking change? IMPOSSIBRU! And since your API does not use any kind of smart pointer to manage it's objects, then you do have memory-related problems. – DeadMG Sep 02 '12 at 16:13
  • @deadmg: you can try use it and find the memory problems. Tell us when your research on it is finished. – tp1 Sep 02 '12 at 16:18
  • @tp1: Well, that's pretty simple. `BM b = bitmapapi.loadbitmap(...); bitmapapi.growbitmap(b, 0,0,0,0); bitmapapi.growbitmap(b,0,0,0,0);` What now? Didn't call your memoize function. Ooops. More relevantly, you can present an API like mine but delegate the implementation to whatever you want... including something like yours, if you're insane. There's no reason to present what you have as a public API. – DeadMG Sep 02 '12 at 16:20
  • @deadmg: except your example again doesn't do anything. (failed to notice it's functional programming and all return values need to be handled -- also the 0's are not doing anything special with memory..) – tp1 Sep 02 '12 at 16:22
  • 1
    @tp1: But you didn't take any care to see that I did handle them. You just said "HANDLE THEM" without doing anything about it. I didn't handle them and now what? Instead of using an RAII class which does not permit such mistakes. If you had used `unique_ptr` it would not be possible to write code like that. – DeadMG Sep 02 '12 at 16:23
  • @deadmg: you don't understand it yet. There is no problems like what you're describing... – tp1 Sep 02 '12 at 16:26
  • @tp1: Your comments indicate semantics that do definitely exhibit such problems. Why don't you explain about how your API makes it impossible to make errors? – DeadMG Sep 02 '12 at 16:27
  • @deadmg: did you notice object lifetimes are managed in Env class -- the api itself never passes ownership or other memory related stuff. – tp1 Sep 02 '12 at 16:29
  • 1
    @tp1: I noticed that the Env can be destroyed. That's pretty much it. There doesn't appear to be any functionality to manage objects, at all. If I wanted to manage memory more fine grained than "Everything I ever created" or "Nothing", it would appear that I'm screwed. – DeadMG Sep 02 '12 at 16:33
  • @deadmg: guess you're screwed. But it's your design that does it. – tp1 Sep 02 '12 at 16:34
  • You're right. How could anyone, ever, want to free some bits of memory but not others? That's a complete fail on their part. Also, you still haven't addressed what happens if I keep around BM objects I wasn't supposed to. – DeadMG Sep 02 '12 at 16:36
  • @deadmg: the trick is that BM objects do not take megabytes of memory like you expect. Only once you pass it to rendering functions, some memory is allocated for the texture. – tp1 Sep 02 '12 at 16:38
  • @tp1: Great, so you lazily allocated the memory that I can't possibly free, ever, whilst the game is running. Thanks so much for that. Also, what if I keep BMs I wasn't supposed to? – DeadMG Sep 02 '12 at 16:39
  • @deadmg: nothing special happens. It still gets destroyed at env destructor. – tp1 Sep 02 '12 at 16:41
  • 4
    Please take any extended conversation to [chat]. Can any useful information be incorporated in the question or an answer? – ChrisF Sep 02 '12 at 18:19

2 Answers2

14

There is in-fact a book that is precisely what you seek. It is call, appropriately enough, API Design for C++.The book's website has source code from the book and Errata as well.

5

This is pretty much impossible. The simple fact is that sometimes, you need the compiler to do a job, and you can't just magic that necessity away. There is no function that can make std::vector not a header-only library. The compiler can make many magics work, but you can't have them without invoking it, and that's a fact of life.

Here's what you can do: don't use templates where you don't need them. Here's what you can't do: anything else.

The simple fact is that recompiling with the new version really isn't that big of a burden compared to the advantages of performance, safety, and functionality you can get with statically typed libraries.

DeadMG
  • 36,794
  • 8
  • 70
  • 139
  • 3
    I mentioned that as an example to think about. what I'm looking for is guidance on other similar issues which I should prepare for, and best practices to handle those. – johannes Sep 02 '12 at 17:16
  • 1
    Well, if all new versions breaking ABI-compatibility are put into a new inline-namespace, what does it matter whether it's a header-only library or not? – Deduplicator Oct 15 '15 at 00:56