as promised, i asked bert hubert how he uses C++ in PowerDNS without damaging himself:

On Mon, Feb 12, 2018 at 12:43:16PM -0800, Paul Vixie wrote:
you seem to have made peace with C++. i predict that you did this by
declaring some subset of its features that you'd be willing to use, and
forbidding all others. if so, can you tell me what the subset is, and
how if at all you enforce it in your code base?


he wrote back as follows, and also gave permission to be quoted here:

bert hubert wrote:
You guess right! I think this might make a good blog post in fact. Various
Linux kernel developers have read PowerDNS source code and most commented
this was the first bit of C++ they truly understood and could appreciate.

The GCC compiler people have also decided to use C++, which is also
something of a vote of confidence from some pretty discerning folks.

So in short, my guidelines consist of first reading the four thin books by
Scott Meyer: Effective C++, More Effective C++, Effective STL, Effective
Modern C++.

Especially the first book covers a lot of the "you can do tons of things in
C++, but please don't".

Things to not use or do (unless you have very good reason):

  * multiple inheritance
  * or in fact even more than the most basic of inheritance of classes.
  * explicit memory allocations (new/delete, except when you really have to)
  * Templates 'because you can'
  * build big object hierarchies, go wild with OO
  * C++ native I/O for big files or file operations (not very good, slow)
  * Do not treat the C++ specification as a personal bucket list

Things to actually do:

  * Trust the compiler writer, use C++ to do heavy lifting
  * Use built-in algorithms (sort, find etc)
  * use smart pointers, spend some time learning std::unique_ptr, which has
    no overhead and frees automatically
  * Use 'Resource Acquisition Is Initialization' (RAII) for resources you must 
free
  * auto all the things
  * build specific utility classes for your projects (DNSName, ComboAddress)
  * Start off with C++ 2014, C++ 2011 if you must
  * use std::thread, std::atomic
  * use exceptions for error handling
  * Use parts of boost that are good (fmt, multi_index, string alghoritm for
    example)
  * Use old school C functions for unixy things

The RAII technique goes like this:

struct ReadFP : boost::non_copyable
{
        ReadFP(std::string&  fname)
         {
            d_fp = fopen(fname.c_str(), "r")
            if(!d_fd)
                throw runtime_error("Opening file "+fname+": "+strerror(errno);
        }
        ~ReadFD()
        {
                fclose(d_fp);
        }
        FILE* d_fp;
};

Written like this, you'll never leak an fd 'ever'. The 'boost::non_copyable'
makes sure no one can copy this struct, which would complicate things. Use:

ReadFD fp("/etc/passwd");
fgets(line, sizeof(line), fp.d_fp);

If you do anything with sockets and IP addresses, you might enjoy my
BSD-licensed code here: https://github.com/ahupowerdns/simplesocket (this
has ComboAddress, for example, which is ABI compatible with struct
sockaddr).

As an example of the power of C++, let's say we have this struct:

struct DNSQuestion
{
        time_t t;
        string query;
        uint16_t type;
};

And we store it like this:

vector<DNSQuestion>  vec;

Now let's say we want this sorted on time, we do:

sort(vec.begin(), vec.end(), [](const auto&  a, const auto&  b) {
        return a.t<  b.t;
});

Now that the vector is sorted like this, we can find all entries for a
specific time_t like this:

auto p = equal_range(vec.begin(), vec.end(), t, [](const auto&a, time_t t) {
        return a.t<  t;
});

And now to print what we found:

for(auto iter = p.first; iter != p.second; ++iter) {
        cout<<query<<""<<type<<endl;
}

The nice thing about this code is that if you look at what it compiles down
to, it ends up exactly as you'd write it by hand in C.. except a ton better.
Internally this is literally all written out to actual code that gets
optimized for DNSQuestion.

If I ever write this up for more general consumption I'll let you know.
Also, if you wonder about specific aspects of C++ to use or not to use, I'm
more than happy to share my thoughts. Or if the above isn't clear. Let me
know!

Good luck!

in response to a followup question about enforcement, bert also said:

Not really. there is g++ -Weffc++ which enforces some items out of
the books I mentioned.

I do think that clang has interesting infrastructure:
http://clang.llvm.org/extra/clang-tidy/
lists a lot of this, including checks that look worthwhile. I know
weuse this at PowerDNS too.

--
P Vixie


--
Nmh-workers
https://lists.nongnu.org/mailman/listinfo/nmh-workers

Reply via email to