flyx.org

Personal homepage of Felix Krause

Reasons why C++ sucks

Disclaimer: This list is not and will never be complete (but I may update it if I'm bored). It also contains strong language.

Preprocessor

  • Yeah, it has a fucking preprocessor. The preprocessor is a feature of C because C lacks so many features that the preprocessor is needed. Nobody cared to include tools in C++ to make the preprocessor obsolete, so it still lurks around and takes your firstborn children.
  • You still use the preprocessor to include headers. So if you have a syntax error in one header, let's say, a missing semicolon in the last line, the compiler complains giving a line in a completely different file. The proper way to do it would be to parse headers separately before including them.
  • Oh, and because you still have to use #include, you obviously need those shitty #ifndef guards in every fucking header file. Yeah, if you have a fancy compiler, you can use #pragma once. Well, unless the gcc guys decide to deprecate it.

Type System

  • C++ has a bool type. It is the most idiotic boolean type you will ever see. Firstly, you can use any integral type in a place where you need a boolean value. This leads of course to programming errors like if (i = 2). But if you actually decide to use the bool type, you run into funny stuff, for example: An uninitialized bool variable may be neither true nor false - depending on your compiler, if you define bool a;, both a and !a may evaluate to true.
  • Enums are really dumb. Take for example:

    enum traffic_lights {
        RED     = 1,
        YELLOW  = 2,
        GREEN   = 4
    };
    

    As you may expect, this is just an int with some named constants. You can declare multiple values with the same value, you can assign int value to it. And if you do YELLOW++, you don't end up with GREEN, but with a value that isn't defined in the enum (but doesn't raise an exception either). You also cannot iterate over existing enum values. At this point, this is just useless syntax sugar for

    #define RED    1
    #define YELLOW 2
    #define GREEN  4
    
  • Oh, did you know, C++11 does introduce enum class. It fixes none of the issues described above, but makes you prefix the enum values with the name of the enum. Well done.

  • Strings are still C strings. Yeah, you may have heard of std::string, which is a type that is somewhat better than a raw char*, but the problem is, string literals are still char*. They get converted to std::string in some places, but it does not work everywhere. For example, this doesn't compile: "a" + "b".

  • Typedefs everywhere! If the error message of a compiler (at least gcc) mentions for example std::string, it does not output std::string, but std::basic_string<char>, because it's a typedef. This gets really ugly with more complex types.

Functions

  • Function parameters are mutable by default. This is bullshit. The usual case is that you don't want to modify a function parameter, because they are passed by value and won't be copied back. It is also horribly inconsistent: Reference type parameters (those with myriads of & around them) are actually always const (that is, you cannot change the reference, but you can change the referenced value).
  • Functions that don't have void as return type are not required to return a value. Seriously? This just screams for bugs if someone somewhere forgets to write return result; and the compiler doesn't remind him.

Templates

  • You have to put the complete implementation into the header. This slows down compilation considerably, because all the fucking implementation of the fucking template is parsed every fucking time it is fucking used. Oh, you can of course try to use precompiled headers and open the door to hell.
  • You can use the keywords typename and class for template parameters, and they do exactly the same. You can put a class into a typename parameter, and you can put a non-class into a class parameter. So what's the point?
  • If you use a template parameter for defining a type within the template implementation, you often have to put typename in front of it. Example:

    template<typename T> a() {
       typename std::vector<T>::iterator t;
    }
    

    It wouldn't compile without the typename. And if you miss it, the compiler will probably give you an error that is extremely hard to understand. If you get some huge error message when compiling a template implementation, add more typename.

  • You cannot constrain type parameters. For example, you cannot declare that a type parameter has to be a child class of some other class. You just assume random things about the template type, and if someone else uses in a way you didn't plan for, he may get error messages pointing to the implementation of your template. There was a feature called Concepts that was planned for C++11, but it was dropped (and may come in C++14).

  • Support for value parameters is very limited. For example, you cannot declare a template taking a parameter of type std::string. You can declare a template parameter of type char*, but you cannot directly pass a string literal to it. You have to define a char* constant with external linkage somewhere and use that as template parameter.

Object Orientation

  • this is a pointer. Why isn't it a reference? It may never be null, and if it is, your code is broken anyway.
  • The compiler generates some methods of a class automatically based on complicated rules. Examples are the assignment operator, a copy constructor and such. You can also instruct the compiler to not generate these methods if they would be automatically generated. Some of these methods are needed for using the class in the standard container structures like std::vector, so you have to check all this stuff every time you declare a class.

Standard Library

  • The smart pointers (std::unique_ptr et. al.) are a sorry excuse for a missing language feature. A class usually has no idea about whether it is accessed with a smart pointer or not, but when it passes a reference to itself somewhere, it needs to know. So you suddenly have to derive from std::enable_shared_from_this to be able to convert this to a smart pointer.
  • Iterators are simply a huge mess. To implement a custom iterator, you kind of need the iterator module from the Boost library if you want to have it done till the end of the year, and even that is really complicated to use.

Tags: programming