c++ criticism

some of these issues are inherent from c, some are unique to c++ and most have been solved in more recent languages like rust and go.

  • no reference compiler
  • no standard build system
  • multiple -sometimes more than 10- ways to do the same thing (see the infamous struct initialization gif)
  • no standard project structure, multiple ways to provide a library
  • multiple ways to consume a library
    • header only, separately compilable source
    • even more tragic with c++20 modules
    • in many cases consuming a thirdparty library will require an intermediate step between grabbing the source and using it from code (ex: openssl)
    • absence of directory structure convention lead to the question: should I write -Ithirdparty/mylib, -Ithirdparty/mylib/include or -Ithirdparty/mylib/src?
  • function overloading combined with implicit type casting is a recipe for disaster
    • can be solved by things like -Wconversion -Werror but again non cross-platform solution that requires extra knowledge that is not explicitly documented as a solution for that specific problem
  • multiple methods for error reporting
    • each function in std::filesystem has at least two declarations, one that throws exceptions and one that does not
    • exceptions can be used at panic situations but can you guarantee that libraries that you use do the same thing ?
  • no UTF-8 support provided by the language, for example: iterate code points of a string instead of iterating bytes
  • painful to navigate through standard library source code in most implementations
  • painful to get something useful from error messages for code that uses templates
  • language provided way of printing text is massively outperformed by thirdparty libraries (see libfmt), happens at other tasks as well, in a language marketed with the term "zero cost abstraction"
  • must type a function signature twice if you want to have a separate compilation unit for it (inherent from c)
  • no reflection support (at least without doing nasty hacks), reflection makes it easy to implement:
    • pretty printing
    • serialization and deserialization
      • for cross program communication
      • for saving and loading configuration or primitive data
    • ORM libraries
  • relatively hard to cross compile
  • relatively hard to produce a binary that is cross-linux-distribution portable
    • libc compatibility
    • statically vs dynamically linked libstdc++ issues
  • community approved way of building programs and providing libraries is in fact cmake

    • it does not build your code but generates a build configuration that is specific to build tools and compilers, because it was too late to force compilers to support a set of flags/arguments and hence too difficult to interact with compilers directly
    • generated configuration (just like any computer generated code) is unreadable
    • fails to unify the experience of having some options in a cross-environment way, ex:

      • having debug symbols in a separate file other than actual program
      • linking statically against standard library
      • specifying build type in a cross platform way (release/debug)
      cmake . -Bbuild && cmake --build build/ --config Release # vcxproj
      cmake . -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build/ # makefile
      
    • procedural language instead of an easy to play with declarative configuration

    • cmake does not check CMakeLists.txt for misplaced, duplicate or no-effect options

    • has IDE specific project generators, while this can be handy it puts an extra burden on cmake development

      • build config should be simple enough that a basic parser can extract code analysis information from it

advantage:

  • most good software is written in c and it is relatively easy to interact with c from c++ and start adding light weight abstractions

Leave a Reply