Enrico Zini: cxx11-talk-examples
C++11 talk examples
On 2014-11-27 I gave a talk about C++ and new features introduced with C++11:
these are the examples. They are all licensed under the wtfpli version
2. See cxx11-talk-notes for the talk notes.
Note that the wrapper interfaces turns errors from the underlying libraries
into exceptions, so the method calls just do what they should, without the need
of documenting special return values for error messages, and removing the need
for each library to implement yet another way of reporting errors.
Also note that all wrapper objects do RAII: you create them and they clean
after themselves when they go out of scope.
The wrapper objects also have cast operators to make them behave as the pointer
or handle that they are wrapping, so that they can be transparently passed to
the underlying libraries.
(note: I had to add
ezhash.cpp
Example usage
Simple sqlite bindings
Remarkably simple sqlite3 bindings based on lambda callbacks.
ezsqlite.h
ezsqlite.cpp
Example usage
A fast Directory object
This is a lightweight wrapper around
ezfs.cpp
Example usage
U+2063 INVISIBLE SEPARATOR to prevent noreturn
statements to be misinterpreted by the blog formatter. If you copypaste the
code and encounter issues, you may want to delete the noreturn statements and
retype them)
A gcrypt hash class
This class is a light wrapper around gcrypt's hashing
functions.
ezhash.h
#ifndef EZHASH_H
#define EZHASH_H
#include <string>
#include <gcrypt.h>
namespace ezhash
class Hash
protected:
// members can now be initialized just like this, without needing to repeat
// their default assignment in every constructor
gcry_md_hd_t handle = nullptr;
public:
Hash(int algo, unsigned int flags=0);
~Hash();
// Assign 'delete' to a method to tell the compiler not to generate it
// automatically. In this case, we make the object non-copiable.
Hash(const Hash&) = delete;
Hash(const Hash&&) = delete;
Hash& operator=(const Hash&) = delete;
// Add a buffer to the hash
void hash_buf(const std::string& buf);
// Add the contents of a file to the hash
void hash_file(int fd);
// Get a string with the hexadecimal hash
std::string read_hex(int algo=0);
/// Pretend that we are a gcry_md_hd_t handle
operator gcry_md_hd_t() return handle;
;
#endif
#include "ezhash.h"
#include <unistd.h>
#include <errno.h>
#include <string>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <stdexcept>
using namespace std;
namespace ezhash
namespace
// noreturn attribute, to tell the compiler that this function never returns
[ [noreturn]] void throw_gcrypt_error(gcry_error_t err)
string msg;
msg += gcry_strsource(err);
msg += "/";
msg += gcry_strerror(err);
throw runtime_error(msg);
string errno_str(int error)
char buf[256];
#if (_POSIX_C_SOURCE >= 200112L _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
strerror_r(errno, buf, 256);
string res(buf);
#else
string res(strerror_r(errno, buf, 256));
#endif
return res;
[ [noreturn]] void throw_libc_error(int error)
throw runtime_error(errno_str(error));
Hash::Hash(int algo, unsigned int flags)
gcry_error_t err = gcry_md_open(&handle, algo, flags);
if (err) throw_gcrypt_error(err);
Hash::~Hash()
gcry_md_close(handle);
void Hash::hash_buf(const std::string& buf)
gcry_md_write(handle, buf.data(), buf.size());
void Hash::hash_file(int fd)
char buf[4096];
while (true)
ssize_t res = ::read(fd, buf, 4096);
if (res < 0) ezfs::throw_libc_error();
if (res == 0) break;
gcry_md_write(handle, buf, res);
std::string Hash::read_hex(int algo)
unsigned char* res = gcry_md_read(handle, algo);
unsigned int len = gcry_md_get_algo_dlen(
algo == 0 ? gcry_md_get_algo(handle) : algo);
// Format the hash into a hex digit
stringstream hexbuf;
hexbuf << hex << setfill('0');
for (unsigned i = 0; i < len; ++i)
hexbuf << setw(2) << (unsigned)res[i];
return hexbuf.str();
ezhash::Hash sha256(GCRY_MD_SHA256);
sha256.hash_buf("ciao\n");
sha256.hash_buf("foo\n");
cout << sha256.read_hex() << endl;
#ifndef EZSQLITE_H
#define EZSQLITE_H
#include <sqlite3.h>
#include <string>
#include <functional>
#include <stdexcept>
namespace ezsqlite
/// RAII wrapper around a sqlite3 database handle
class DB
protected:
sqlite3* handle = nullptr;
public:
// Open a connection to a SQLite database
DB(const std::string& filename, int flags=SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE);
DB(const DB&) = delete;
DB(const DB&&) = delete;
DB& operator=(const DB&) = delete;
~DB();
/**
* Execute a query, optionally calling 'callback' on every result row
*
* The arguments to callback are:
* 1. number of columns
* 2. text values of the columns
* 3. names of the columns
*/
// std::function can be used to wrap any callable thing in C++
// see: http://en.cppreference.com/w/cpp/utility/functional/function
void exec(const std::string& query, std::function<bool(int, char**, char**)> callback=nullptr);
/// Pretend that we are a sqlite3 pointer
operator sqlite3*() return handle;
;
#endif
#include "ezsqlite.h"
namespace ezsqlite
DB::DB(const std::string& filename, int flags)
int res = sqlite3_open_v2(filename.c_str(), &handle, flags, nullptr);
if (res != SQLITE_OK)
// From http://www.sqlite.org/c3ref/open.html
// Whether or not an error occurs when it is opened, resources
// associated with the database connection handle should be
// released by passing it to sqlite3_close() when it is no longer
// required.
std::string errmsg(sqlite3_errmsg(handle));
sqlite3_close(handle);
throw std::runtime_error(errmsg);
DB::~DB()
sqlite3_close(handle);
namespace
// Adapter to have sqlite3_exec call a std::function
int exec_callback(void* data, int columns, char** values, char** names)
std::function<bool(int, char**, char**)> cb = *static_cast<std::function<bool(int, char**, char**)>*>(data);
return cb(columns, values, names);
void DB::exec(const std::string& query, std::function<bool(int, char**, char**)> callback)
char* errmsg;
void* cb = callback ? &callback : nullptr;
int res = sqlite3_exec(handle, query.c_str(), exec_callback, cb, &errmsg);
if (res != SQLITE_OK && errmsg)
// http://www.sqlite.org/c3ref/exec.html
//
// If the 5th parameter to sqlite3_exec() is not NULL then any error
// message is written into memory obtained from sqlite3_malloc() and
// passed back through the 5th parameter. To avoid memory leaks, the
// application should invoke sqlite3_free() on error message strings
// returned through the 5th parameter of of sqlite3_exec() after the
// error message string is no longer needed.
std::string msg(errmsg);
sqlite3_free(errmsg);
throw std::runtime_error(errmsg);
// Connect to the database
ezsqlite::DB db("erlug.sqlite");
// Make sure we have a table
db.exec(R"(
CREATE TABLE IF NOT EXISTS files (
name TEXT NOT NULL,
sha256sum TEXT NOT NULL
)
)");
// Read the list of files that we know
map<string, string> files;
db.exec("SELECT name, sha256sum FROM files", [&](int columns, char** vals, char** names)
if (columns != 2) return false;
files.insert(make_pair(vals[0], vals[1]));
return true;
);
O_PATH file descriptors for directories.
I'd love to see a library of well-maintained and thin C++ bindings around libc,
that do little more than turning errors into exceptions and making it also work
with std::string buffers.
ezfs.h
#ifndef EZFS_H
#define EZFS_H
#include <string>
#include <functional>
#include <memory>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
namespace ezfs
class Directory
protected:
int handle = -1;
public:
Directory(const std::string& pathname, int flags=0);
~Directory();
Directory(const Directory&) = delete;
Directory(const Directory&&) = delete;
Directory& operator=(const Directory&) = delete;
/// List the directory contents
void ls(std::function<void(const dirent&)> callback);
int open(const std::string& relpath, int flags, mode_t mode=0777);
;
std::string errno_str(int error=errno);
[ [noreturn]] void throw_libc_error(int error=errno);
#endif
#include "ezfs.h"
#include <stdexcept>
#include <memory>
#include <cstring>
#include <cstdlib>
#include <string>
#include <linux/limits.h>
using namespace std;
namespace ezfs
string errno_str(int error)
char buf[256];
#if (_POSIX_C_SOURCE >= 200112L _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
strerror_r(errno, buf, 256);
string res(buf);
#else
string res(strerror_r(errno, buf, 256));
#endif
return res;
[ [noreturn]] void throw_libc_error(int error)
throw runtime_error(errno_str(error));
Directory::Directory(const std::string& pathname, int flags)
handle = ::open(pathname.c_str(), O_PATH O_DIRECTORY flags);
if (handle < 0) throw_libc_error();
Directory::~Directory()
::close(handle);
void Directory::ls(std::function<void(const dirent&)> callback)
int fd = openat(handle, ".", O_DIRECTORY);
if (fd < 0) throw_libc_error();
// RAII Self-cleaning DIR object
unique_ptr<DIR, std::function<void(DIR*)>> dir(fdopendir(fd), [](DIR* dir) if (dir) closedir(dir); );
if (!dir)
// fdopendir(3): After a successful call to fdopendir(), fd is used
// internally by the implementation, and should not otherwise be used
// by the application.
//
// but if the fdopendir call was not successful, fd is not managed by
// DIR, and we still need to close it, otherwise we leak a file
// descriptor.
//
// However, close() may modify errno, so we take note of the errno set
// by fdopendir and raise the exception based on that.
int fdopendir_errno = errno;
close(fd);
throw_libc_error(fdopendir_errno);
// Size the dirent buffer properly
const unsigned len = offsetof(dirent, d_name) + PATH_MAX + 1;
unique_ptr<dirent, std::function<void(void*)>> dirbuf((dirent*)malloc(len), free);
while (true)
dirent* res;
int err = readdir_r(dir.get(), dirbuf.get(), &res);
// End of directory contents
if (err == 0)
if (res)
callback(*res);
else
break;
else
throw_libc_error(err);
int Directory::open(const std::string& relpath, int flags, mode_t mode)
int res = openat(handle, relpath.c_str(), flags, mode);
if (res < 0) throw_libc_error();
return res;
// This is almost the equivalent of running "sha256sum ."
ezfs::Directory dir(".");
dir.ls([&](const dirent& d)
if (d.d_type != DT_REG) return;
ezhash::Hash sha256(GCRY_MD_SHA256);
// I have no RAII wrapper around file handles at the moment, so
// I'll have to use a try/catch for cleaning up after errors
int fd = dir.open(d.d_name, O_RDONLY);
try
sha256.hash_file(fd);
close(fd);
catch (...)
close(fd);
throw;
cout << sha256.read_hex() << " " << d.d_name << endl;
);
A week ago,
This is, essentially, a call for help, as I don't really know which program
is at a fault here.
Given that Emacs's upstream
and gives a preview of the wide range of commercial opportunities that WebRTC is creating for software vendors to displace traditional telecommunications providers.
xTupleCon also gave me a great opportunity to see new features (like the
I've rebuilt many Debian packages over the years, largely to fix bugs which affected me, or to add features which didn't make the cut in various releases. For example I made a package of fabric available for Wheezy, since it wasn't in the release. (Happily in that case a wheezy-backport became available. Similar cases involved repackaging gtk-gnutella when the protocol changed and the official package in the lenny release no longer worked.)
I generally release a lot of my own software as Debian packages, although I'll admit I've started switching to publishing Perl-based projects on CPAN instead - from which they can be debianized via
Even before I install the app to find out if the government is monitoring me, Amnesty is keen to monitor my behaviour themselves.
While cookies are used widely, their presence on a site like Amnesty's only further desensitizes Internet users to the downside risks of tracking technologies. By using cookies, Amnesty is effectivley saying a little bit of tracking is justified for the greater good. Doesn't that sound eerily like the justification we often hear from governments too?
Is Amnesty part of the solution or part of the problem?
Amnesty is a well known and widely respected name when human rights are mentioned.
However, their advice that you can install an app onto a Windows computer or iPhone to detect spyware is like telling people that putting a seatbelt on a motorbike will eliminate the risk of death. It would be much more credible for Amnesty to tell people to start by avoiding cloud services altogether, browse the web with
Write to Amnesty
Amnesty became famous for their letter writing campaigns.
Maybe now is the time for people to write to Amnesty themselves, thank them for their efforts and encourage them to take more comprehensive action.
Feel free to cut and paste some of the following potential ideas
A common way to build a firewall ruleset is to run a shell script
calling
I've been crap about blogging lately. Let's see if I can fix
that.
Back in February and March, Jo and I went on vacation for 2 weeks
touring California and Nevada. We had an awesome time and we got to
see and do lots of fun stuff. I'm not going to go into all the
details, as it's a long time ago now...! I've got a massive set
of
I guess I'm not the only one who's been annoyed by shower curtains
sticking to me in the shower, but I'd not really paid much thought to
it until now. Suddenly, as of maybe 18 months ago I'm seeing most
hotel bathrooms replacing the straight curtain track with a curved
one, to stop that happening. This photo shows that process with both
tracks visible...
Waterproof/washable TV remotes
This one really surprised me. As Jo will attest, I
have a little bit of an obsession with TVs and set-top boxes in hotel
rooms. This dates from my time working for Amino where we made set-top
boxes, and I got into the habit of checking what products were in the
hotels I stayed in. I've seen a range of weird and wonderful setups
over the years, but never this one before. In two of the hotels on our
trip, they had replaced the normal TV remotes with washable/wipe-down
ones. Weird...


