HN user

bstamour

303 karma
Posts1
Comments141
View on HN

You're right. Lambdas in C++ are syntactic sugar over something the core language has allowed you to do since before C++98. Since you control which variables you capture into the closure, and how, when writing the lambda, all of the information regarding how to make it (e.g. it's size, data members, etc) is static, and so it does not require the use of the heap at all. A concrete example. The following C++ examples do the same thing, and neither touch the heap:

    // A. Using a struct. The old manual way.
    struct my_lambda {
        my_lambda(int c) : c_(c) {}
        int operator() (int x) const {
            return x == c_;
        }
        int c_;
    };
    
    auto f(vector<int> numbers) {
        my_lambda lam(2);
        // remove all the matching elements
        erase_if(numbers, lam);
        return numbers;
    }

    // B. Using a lambda
    auto g(vector<int> numbers) {
        int c = 2;
        erase_if(numbers, [c](int x) { return x == c; });
        return numbers;
    }

Internally, lambdas are structs with the "function call" operator overload. Context is done via members of the struct: capture by-value, and the struct copies them and stores its own, capture by reference, and the struct member is a reference. There should be zero heap allocation in any case.

Progress on Plasma 6 years ago

Slackware. I use the Plasma5 packages maintained by Eric Hameleers, and it's a wonderful experience.

We use Delphi for some of our older applications (everything new is migrating to either C++17 or Go). I remember upgrading the IDE (forget which version, but it was about 3 years ago) and after loading my project, I hit F1 to bring up the help menu. The whole IDE crashed... Between little surprises like that and the insane licensing price, I'm glad we're moving off of it. I don't have any objections to the language itself, but the tooling just isn't where it needs to be.

Lock guard has no default constructor, so the line will in fact materialize a temporary lock guard around the mutex m, then throw it away at the semi-colon, thus locking nothing.

You can add a literal operator:

    auto operator "" _r(char const* str, unsigned long) {
      return std::regex{str};
    }
To avoid all the backslashes, you can use a raw string literal:
    int main() {
      auto myre = R"(^hello\w*)"_r;
    }

Concrete example:

  void foo(const int* const p1, int* const p2) {
    int a = *p1;
    *p2 += 42;
    int b = *p1;
    return a == b; // b = a + 42
  }
  int main() {
    int x = 0;
    return foo(&x, &x);
  }

You're right, but what I meant about it was that just because the variable is const, doesn't mean it can't change from somewhere else between reads. Even if you use synchronization to avoid data races, if you read the pointer to const twice in the function, it could change between the reads.

If the initial object itself isn't const, then merely declaring the function parameter as a pointer to const won't guarantee that some other thread of execution won't change the value under your nose. Or if you have multiple pointer parameters, they can alias each other.

Indirection in C and C++ is a mess, but at least C has the "restrict" keyword. Best to program with value types whenever you can, and use pointers and references when you must.

readonly was the original proposed name, if I remember my D&E [0] correctly. Bjarne outlined in that book why he went with const instead, but I forget why off the top of my head. I guess it's tine for a re-read!

[0] The Design and Evolution of C++

The examples in the articles are non-constant pointers to constant data. If you want to declare the pointer itself const, you need to do it after the asterisk.

    const int* const 
instead of
    const int*

But in languages that support multiple dispatch at the language level, they're just another way of writing polymorphic functions. They're not just a niche feature. When you don't have to write all of the ceremony of the visitor pattern, it's easier to use visitors everywhere without thinking about them.

Boost came about from a few members of the ISO C++ committee as a way to iterate on library features. It would be a shame if none of that work made it's way back into the standard.

Knuth defines effectiveness as: "... all of the operations to be performed in the algorithm must be sufficiently basic that they can in principle be done exactly and in a finite length of time by a man using paper and pencil."

K-means and other heuristic algorithms fit that description.

It's an example of uniform initialization syntax that was brought into the language in C++11. It simplifies some things (no narrowing conversions allowed) but also complicates things (if any constructor takes in an initialize-list, it gets priority). In this case, the code is constructing an object of type weekday from an expression that represents that particular date.

The joy of max() 8 years ago

No it won't. You'll get a compile time error, as T could either deduce to int or double. Unless you explicitly specify it as max<int>(1, 2.0) or max<double>(1, 2.0).

The joy of max() 8 years ago

C++'s type system has always been stricter than C's. Even the following, totally valid C program, is ill-formed C++

    int* x = malloc(5 * sizeof (int));
because in C++ you cannot implicitly cast a void pointer.