1. 14

  2. 3

    Good, general stuff. These sorts of things need to become more idiomatic and commonplace.

    One suggestion regarding “Wrap your structs in a typedef”. Instead of declaring struct foo and then later defining typedef struct foo { /* ... */ } foo, I have actually found it much nicer to write typedef struct foo foo in the header declaration, and then later simply define struct foo { /* ... */ }. This allows the forward-declarations to access the typedef as well, so that everyone can be consistent.

    1. 2

      The thing with named optional arguments is interesting. I was unaware that there was a guarantee of zero initialisation for the fields you didn’t name. The C++ version of this is a bit nicer though:

      struct Arguments
              bool thing = false;
              int y = 12;
      int x(Arguments &&);
      int y()
              return x({.thing = true});

      Here, the argument structure passed into x has all of its fields set to either the defaults or the explicitly specified value. Even better, overloading in C++ lets you add a version that takes a newer version of the arguments structure and not expose the old one in the header, giving newly-compiled code access to the new function and making old code still call the old one.

      There’s still a lot of outdated ‘optimization advice’ about passing and returning structs by value in C and C++ around. In C++ this advice is sometimes even justified because copying a non-trivial C++ object may be much more expensive than it looks on the surface because complex custom copying code might be invoked under the hood (passing std::string objects by value is the best/worst example).

      C++ guarantees return-value elision since C++14, so there’s no problem returning an object by value: the caller allocates space and the object is constructed there. C++11 r-value references and move construction let do something equivalent to by-value arguments, for deep structures (in C, you can copy a structure containing pointers by simple assignment, and now you probably have a memory management bug).

      Yeah I know I knooow… theoretically RAII is about general resource management, not just about memory. But at least in my experience, it’s always about memory management.

      No, not even close. ’std::lock_guard` and friends are some of of the most common uses of RAII in modern C++. It’s also used for managing file descriptors / OS handles, where you need to make sure that it’s released on all code paths. Memory management is the simplest case.