Modern C++

Modules (C++20) “Modules are othogonal to namespaces.” lvalues and rvalues An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it. A function call can be an lvalue if and only if the return value is a reference. [Read More]

KEYnote

A Linux JUCE application that extracts the peak FTT bin from a live audio recording and reports the closest note

Screenshot is highlighting the major 3rd of an A chord: 440, 550 and 660Hz. Note the FFT bin is not a precise pitch so the closest concert pitch is displayed. See the source on GitHub. Note mapping #include <iostream>#include <map>#include <vector> const std::map<double, std::string> notes{ // Catch all for lower bound search {0.0, "Bx"}, // All the notes we're interested in. At the low end a single Fourier bin // will map to multiple notes. [Read More]

How does your vector grow?

How many times is the destructor for the “fax” class called below after populating a five element STL vector? std::vector<fax> y; for (size_t i = 0; i < 5; ++i) y.push_back(fax()); Remarkably it’s 17 times! Run the code on compiler explorer. For each push we call the default constructor to create a transient object and then call the copy constructor to populate the new element with its data. So far so good. [Read More]

Bird in a bird

How many times is the destructor called?

struct bird { ~bird() { std::puts("in a bird"); } }; bird in = bird(bird(bird(bird(bird())))); The destructor is called once! Thanks to C++'s return value optimisation. You can disable this behaviour by passing -fno-elide-constructors to the compiler. However, if you’re using a standard later than C++14 then it happens regardless. So does this mean we can’t let copy constructors cause side-effects, lest the compiler doesn’t bother calling them? See copy elision and run the example in Compiler Explorer. [Read More]

Modern C++ migration

Welcome to the std::promised land

Auto Type inference is a game changer. Essentially you can simplify complicated (or unknown) type declarations with auto. But it can be a balance of convenience over readability. int x1 = 5; // Explicit auto x2 = 5; // What's the underlying type? std::vector<std::string> moon = {"Don't", "look", "at", "the", "finger"}; auto finger = moon.front(); And there are a few perfectly valid gotchas. Let’s create a variable and a reference to it, updating y2 (below) also updates y1 as expected. [Read More]