3

I'm writing a library with many asserts. The library is much slower with asserts turned on and the whole point of the library is that it is fast, so the asserts only make sense when testing or diagnosing a bug. I'm using autoconf and it seems to be standard practice to require the user to know about this issue and pass a flag to configure to disable asserts. In that case only an expert user will know enough to install an appropriate version of the library! Is that really what I should do, and if so, are there good reasons for that beyond just "that's what expert users and other programmers will expect?"

Edit: Here's an example of a discussion stating that you should not define NDEBUG by default in release mode, though with no other reason given that it is surprising to do that.

Bjarke H. Roune
  • 3,667
  • 2
  • 22
  • 26
  • 1
    You should build two versions of the library, debug with asserts and release optimized with no asserts. Also consider leaving *cheap* asserts in release builds (if they won't affect performance, measure!) – David Rodríguez - dribeas Jul 27 '12 at 20:07
  • @dribeas That's a good idea (http://stackoverflow.com/questions/11695046/how-to-have-library-builds-with-asserts-turned-on-and-off-side-by-side) though that also seems to be non-standard at least on unix platforms. That still leaves the question if the library with no special modifier added to the name should be the assert one or the non-assert one. Also, if the user doesn't ask for two versions, should the default be with asserts or not. I'd say that the asserts should only be there for people who ask for them, but that seems contrary to standard practice, and I'm wondering why that is. – Bjarke H. Roune Jul 27 '12 at 20:27
  • @DavidRodríguez-dribeas Oh wait, I didn't notice that you said "debug with asserts". This question is not about debug builds. It's about the default release version that gets installed when you build from source and do something like "make install". – Bjarke H. Roune Jul 27 '12 at 21:10
  • The default release build of a library should result in two versions of the library, one for debug builds of programs to link with and the other for release builds of programs to link with. Debugging the *library* is a different matter. – Jim Balter Jul 28 '12 at 01:12
  • @JimBalter The question is whether asserts should be turned on for the non-debug version of the library by default. – Bjarke H. Roune Jul 28 '12 at 09:28
  • The whole point of having a debug version in addition to a release version is so you can turn off the asserts. As you said, the whole point of the library is to be fast, so why would there even be a question of whether to make it much slower? When there is both a debug version and a release version, developers don't expect the release version to have asserts because their code is assumed to have been debugged. – Jim Balter Jul 28 '12 at 10:01
  • @JimBalter A debug version is not just about asserts - it for example also has debug symbols and no optimization. I agree that making things slow in a release build seems strange, but there does not seem to be a standard practice on unix systems to define NDEBUG automatically. Hence the question :) Though I guess perhaps the idea is that you can have several levels of asserts, and perhaps you'd want to keep in some of the cheap asserts and then have your own system for disabling the more expensive asserts. Here NDEBUG would strip out everything, so maybe that's why it's not defined by default. – Bjarke H. Roune Jul 28 '12 at 17:34
  • Yes, of course I know a debug version has symbols ... I think you're not comprehending my comment, but I'm not going to try further. Good luck. – Jim Balter Jul 28 '12 at 18:31
  • @JimBalter I'm sorry if I offended you in some way. – Bjarke H. Roune Jul 29 '12 at 00:00

2 Answers2

1

I think I've figured this out now. The problem with defining NDEBUG is that it can lead to undefined behavior. Mine is a template library with some non-template parts, so my code gets inlined into other people's binaries. If I define NDEBUG when compiling the non-inline code, and then the client code gets compiled without NDEBUG, then there will be two incompatible versions of the code from the headers - one with asserts and one without. This leads to undefined behavior and I have encountered this issue as a mysterious crash once before myself. So I do not think that a library should define NDEBUG - the person or build system in charge of compiling everything on a given computer should be the one to decide about NDEBUG.

However, I do not have to define NDEBUG just to make my library run without asserts by default. I now have a macro MYLIB_DEBUG and MYLIB_ASSERT. If MYLIB_DEBUG is not defined then MYLIB_ASSERT(X) does nothing. If MYLIB_DEBUG is defined then MYLIB_ASSERT(X) is defined as assert(X). This makes asserts opt-in without messing with NDEBUG.

So my current answer to my question is that it is fine for a library to turn off asserts by default, just don't do it by defining NDEBUG if your interface has any inline functions that contain asserts.

Bjarke H. Roune
  • 3,667
  • 2
  • 22
  • 26
-1

If use of assert makes your library slow do as you want and turn it off. Make sure it's clearly documented... and stop worrying.

James Morris
  • 4,867
  • 3
  • 32
  • 51