- Globally constructed objects, called before main(). Yes you might say, don't use them, but once you are in C++ land you can't be safe that everything else you've decided to use does not use them.
- Throwing exceptions. This is mostly debugger pain. If you've used (again) without knowledge underlying code/library that uses exceptions (and note, you don't) then you might be inadvertently throwing them to the user.
- RAII does not work with longjmp/setjmp. If you have callback mechanisms, and your client does longjmp on you, this won't work with any RAII done objects.
- C++ runtime. You would be requiring this to be loaded, which might become nuisance in situations where your main application never used C++, you wrote a plugin/shared lib using C++ code, and now there is the requirement. Not a big deal after all.
- C++ runtime again but for MSVC (although it's for the C runtime too to a point). Now while you can make code that is more independent from the "C" runtime for MSVC, it's harder to maintain this for C++ - you might run into issue where mixing dynamically (shared) libraries would have to use different (and even more different through WinSxS) MSVCPxxx.DLL libs (C++ runtime). In all fairness, this is more of a Microsoft mishap, and not caring about backward binary compatibility, but hey it's there.
- Most of all, no matter what you do - you can't expose the really useful C++ things - like stl or qt5 or something else's objects/vectors/strings/maps/etc. Well that's obvious - off course you can, but then you are basically forcing the person using your library to go that route. If your interface is in "C" not only he longer has this pressure, he can use it easier through FFI in plethora of other language/runtimes without writing wrappers, and minimizing the number of precompiled binaries that he has to provide (no linking statically to C++ runtime would turn out bad at the end).
- Case in point - STL's ITERATOR_DEBUG_LEVEL in MSVC. By default it's set to 2, which means make extensive checks of every map<>, vector<>, etc. once they are released. This severely slows down the debug. It's useful, but it's not feature that can be turned on or off. Most of 3rd party libraries, are playing safe and don't do anything special, e.g. they expect ITERATOR_DEBUG_LEVEL=2. But in your production code you might want even your Debug versions to be somewhat faster. Most of your day won't be spent tracking down map<>, vector<>, but other things. As such you go ahead and compile ITERATOR_DEBUG_LEVEL=0, and then .... well you can not link anymore directly to the said 3rd party libs. You either have to precompile them, which might be fine, until you are given Middleware that is not compiled this way. And in all cases it's very important that all these libs use at the end just one runtime, not several (as it happens when you have tons of MSVCRxxx.dll/MSVCPxxx.dll in your running image).
- And there is more. For example for statically build libraries, global constructors might be lost, if there is no symbol referring to them used by the main application. So you might lose some important initialization step.
- etc., etc., etc.