34

One of my major complaints about C++ is how hard in practice it is to pass std library objects outside of dynamic library (ie dll/so) boundaries.

The std library is often header-only. Which is great for doing some awesome optimizations. However, for dll's, they are often built with different compiler settings that may impact the internal structure/code of a std library containers. For example, in MSVC one dll may build with iterator debugging on while another builds with it off. These two dlls may run into issues passing std containers around. If I expose std::string in my interface, I can't guarantee the code the client is using for std::string is an exact match of my library's std::string.

This leads to hard to debug problems, headaches, etc. You either rigidly control the compiler settings in your organization to prevent these issues or you use a simpler C interface that won't have these problems. Or specify to your clients the expected compiler settings they should use (which sucks if another library specifies other compiler settings).

My question is whether or not C++11 tried to do anything to solve these issues?

Doug T.
  • 11,737

3 Answers3

20

You are correct that anything STL - actually, anything from any third party library which is templated - is best avoided in any public C++ API. You also want to follow the long list of rules at http://www.ros.org/reps/rep-0009.html#definition to inhibit ABI breakage which makes programming public C++ APIs a chore.

And the answer regarding C++11 is no, this standard isn't touching that. More interesting is why not? The answer is because C++17 is very much touching that, and for C++ Modules to be implemented we need exported templates to work, and for that we need a LLVM type compiler such as clang which can dump the full AST to disc and then do caller-dependent lookups to handle the many ODR violating cases in any large C++ project - which, by the way, includes lots of GCC and ELF code.

Lastly, I see a lot of MSVC hate and pro-GCC comments. These are very misinformed - GCC on ELF is fundamentally, and irretrievably, incapable of producing valid and correct C++ code. The reasons for this are many and legion, but I'll quickly quote one case example: GCC on ELF cannot safely produce Python extensions written using Boost.Python where more than one extension based on Boost.Python is loaded into Python. That's because ELF with its global C symbol table is simply incapable by design of preventing ODR violations causing segfaults, whereas PE and MachO and indeed the proposed C++ Modules specification all use per-module symbol tables - which incidentally also means vastly faster process init times. And there are plenty more problems: see a StackOverflow I answered recently at https://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 for example where C++ exception throws are irretrievably fundamentally broken on ELF.

Last point: regarding interoping different STLs, this is a big pain for many large corporate users trying to mix third party libraries which are tightly integrated to some STL implementation. The only solution is a new mechanism for C++ to handle STL interop, and while they're at it you might as well fix compiler interop too so you can (for example) mix MSVC, GCC and clang compiled object files and it all just works. I'd watch the C++17 effort and see what turns up there in the next few years - I'd be surprised if nothing does.

9

The specification never ever had this issue. That's because it has concept called "one definition rule", which mandates that each symbol has exactly one definition in the running process.

Windows DLLs violate this requirement. That's why there are all these problems. So it's up to Microsoft to fix it, not C++ standardization committee. Unix never had this problem, because shared libraries work differently there and by default conform to one definition rule (you can explicitly break it, but you obviously only do if you know you can afford it and need to squeeze out the few extra cycles).

Windows DLLs violate one definition rule because:

  • They hardcode from which dynamic library a symbol will be used during static link time and resolve symbols statically within the library that defines them. So if the same weak symbol gets generated in multiple shared libraries and those libraries than get used in single process, the dynamic linker has no chance to merge those symbols. Usually such symbols are static members or class impedimenta of template instances and it than causes problems when passing instances between code in different DLLs.
  • They hardcode whether symbol will be imported from dynamic library already during compilation. Thus code linked with some library statically is incompatible with code linked with the same library dynamically.

Unix using ELF format exports implicitly imports all exported symbols to avoid the first problem and does not distinguish between statically and dynamically resolved symbols until static link time to avoid the second.


The other issue is of compiler flags. That issue exists for any program composed from multiple compilation units, dynamic libraries don't have to be involved. However it's much worse on Windows. On Unix it does not really matter whether you link statically or dynamically, nobody links standard runtime statically anyway (in Linux it might even be illegal) and there is no special debug runtime, so one build is good enough. But the way Microsoft implemented static and dynamic linking, debug and release runtime and some other options means they caused combinatorial explosion of needed library variants. Again platform issue rather than C++ language issue.

Jan Hudec
  • 18,410
6

No.

There is a lot of work going on to replace the header system, feature which is called Modules and which could have an impact on this, but certainly not a big one.

Klaim
  • 14,902
  • 4
  • 51
  • 62