wiki:Languages/CPP

C++

C++ is history repeated as tragedy. Java is history repeated as farce.

If you like C++, you don’t know C++.

C++ is to C as Lung Cancer is to Lung.

BS

Bjarne Stroustrup is a Trump-like populist and demagogue. This explains everything about C++.

C is C++ without the BS.

C++ is a language strongly optimized for liars and people who go by guesswork and ignorance. It has been sold to them, like Java been sold to absolute idiots.

C++17

C++ is a "nightmare" industry-standard implementation language to be used in a rare case when you are know what you are doing and why it is so, and when you already have a working prototype in some prototyping language. It is only suitable to re-implement something in C++ because you absolutely have to.

Use ONLY a small, sane subset of c++17 standard along with Clang -- since c++11 has been actually implemented in clang++ it began to approach the borders of sanity.

Otherwise Go is a much better alternative (especially for prototyping), being an extraordinary well-crafted language. Everything which is only claimed to be good about C++ (expressiveness, static type checking, zero-overhead abstractions, etc.) is indeed better in Go.

clang++ -std=c++17 -stdlib=libc++

Basically, at the time of conception of the first proposals B.S. was (and still is) a narcissistic fucking demagogue, ignorant of most of the current developments in functional languages. He is still a fucking demagogue.

However, literally millions of man-hours has been spent on improving C++ and the current C++17 standard along with clang++ compiler and libc++ C++17 standard library makes it finally usable (with a bit less pain).

    int v[] = {0,1,2,3,4,5,6,7,8,9};

    for (auto& x : v)
        ++x;

    for (auto& x : v)
        cout << x << "\n";

How do we know it is any good?

LLVM/Clang (proves itself by example), Languages/Swift, Android/NDK, Chrome, Libs/Tensorflow and some crap from Facebook, like Tools/HHVM and Tools/PyTorch.


Old plain C

This is an unsophisticated implementation of a Single Linked List

#include <stdio.h>
#include <stdlib.h>

struct list_node {
    struct list_node *prev, *next;
    int value;
};

struct list {
    struct list_node *first, *last;
};

void list_node_init(struct list_node *n, int v) { n->value = v; }

struct list_node *list_advance(struct list_node *n) {
    return n->next;
}

struct list_node *list_begin(struct list *xs) {
    return xs->first;
}
struct list_node *list_end(struct list *xs) {
    return NULL;
}

void list_init(struct list *xs) {
    xs->first = NULL;
    xs->last = NULL;
}

void list_insert(struct list *xs, struct list_node *where, int v) {
    struct list_node *newnode = (struct list_node *)malloc(sizeof(*newnode));
    list_node_init(newnode, v);
    newnode->prev = where ? where->prev : xs->last;
    newnode->next = where;
    if (newnode->prev) newnode->prev->next = newnode;
    if (where) where->prev = newnode;
    if (where == xs->first) xs->first = newnode;
    if (!where) xs->last = newnode;
}
void list_push_front(struct list *xs, int v) {
    list_insert(xs, list_begin(xs), v);
}
void list_push_back(struct list *xs, int v) {
    list_insert(xs, list_end(xs), v);
}

void list_erase(struct list *xs, struct list_node *where) {
    struct list_node *prev = where->prev;
    struct list_node *next = where->next;
    if (prev) prev->next = next;
    if (next) next->prev = prev;
    if (where == xs->first) xs->first = next;
    if (where == xs->last) xs->last = prev;
    free(where);
}

void list_clear(struct list *xs) {
    while (xs->first) list_erase(xs, xs->first);
}

void list_done(struct list *xs) { list_clear(xs); }

int main(void) {
    struct list xs;
    struct list_node *n;

    list_init(&xs);
    list_push_back(&xs, 1);
    list_push_back(&xs, 5);
    list_push_front(&xs, 8);
    list_push_back(&xs, 3);

    for (n = list_begin(&xs); n != list_end(&xs); n = list_advance(n)) {
        printf("%d", n->value);
    }
    printf("\n");

    list_done(&xs);
    return 0;
}

The big idea of original C++ was to *improve* C with better types in the first place, and adding OO features, such as classes, was only part of the process.

Zero cost abstractions meme

What is more important, there was the principle of re-using a mature and battle-tested C compiler whenever possible, so classes were packed as structs, methods were merely ordinary function calls with one extra (-1) argument (single extra pointer allocation on a stack), etc.

Compilers suites, such as gcc or Clang would generate almost exactly the same machine code for C and C++ version of the translated code, like in the example below:

the smallest sane subset of C++

This is an example of a sane, Rust-like C++. Nested structure (NOT classes yet), constructors and destructors, the new keyword, typed references ((T &),

struct list {
    struct node {
        node *prev, *next;
        int value;

        node(int v) { value = v; }
        node *advance() { return next; }
    };

    node *first, *last;

    node *begin() { return first; }
    node *end() { return NULL; }

    list() {
        first = NULL;
        last = NULL;
    }
    ~list() { clear(); }

    void insert(node *where, int v) {
        node *newnode = new node(v);
        newnode->prev = where ? where->prev : last;
        newnode->next = where;
        if (newnode->prev) newnode->prev->next = newnode;
        if (where) where->prev = newnode;
        if (where == first) first = newnode;
        if (!where) last = newnode;
    }
    void push_front(int v) { insert(begin(), v); }
    void push_back(int v) { insert(end(), v); }

    void erase(node *where) {
        node *prev = where->prev;
        node *next = where->next;
        if (prev) prev->next = next;
        if (next) next->prev = prev;
        if (where == first) first = next;
        if (where == last) last = prev;
        delete where;
    }

    void clear() {
        while (first) erase(first);
    }
};

Templates

The original idea was not that bad - generate copies of the same code for each instantiated type and call efficiently it via a single "table look up". The binary becomes fat, but the code is still fast and straightforward.

The real problems of C++ began when they lost the track of this sane, relatively simple, understandable, straightforward C++ -> C -> Assembly -> ABI calls pipeline.

template <typename T>
struct list {
    struct node {
        node *prev, *next;
        T value;

        node(T v) { value = v; }
        node *advance() { return next; }
    };

    node *first, *last;

    node *begin() { return first; }
    node *end() { return NULL; }

    list() {
        first = NULL;
        last = NULL;
    }
    ~list() { clear(); }

    void insert(node *where, T v) {
        node *newnode = new node(v);
        newnode->prev = where ? where->prev : last;
        newnode->next = where;
        if (newnode->prev) newnode->prev->next = newnode;
        if (where) where->prev = newnode;
        if (where == first) first = newnode;
        if (!where) last = newnode;
    }
    void push_front(T v) { insert(begin(), v); }
    void push_back(T v) { insert(end(), v); }

    void erase(node *where) {
        node *prev = where->prev;
        node *next = where->next;
        if (prev) prev->next = next;
        if (next) next->prev = prev;
        if (where == first) first = next;
        if (where == last) last = prev;
        delete where;
    }

    void clear() {
        while (first) erase(first);
    }
};

and then

list<int> xs;
Last modified 4 months ago Last modified on Aug 2, 2019, 8:00:57 AM
Note: See TracWiki for help on using the wiki.