RAII wrapper for SQLite transactions I'm using this nice C++ wrapper to work with SQLite3 in my project. I wanted to handle errors gracefully and automatically rollback if piece of code fails, so wrote this simple helper class:

class SqlTransaction { // RAII class to rollback on error
    public:
        SqlTransaction(std::shared_ptr&lt;sqlite::database&gt; db_): db(db_) { *db &lt;&lt; "begin;"; };
        ~SqlTransaction() { if (!finished) rollback(); };
        void commit() { if (!finished) { *db &lt;&lt; "commit;"; finished = true; } };
        void rollback() { if (!finished) { *db &lt;&lt; "rollback;"; finished = true; } };

        // Disable both copying and moving
        SqlTransaction(const SqlTransaction&amp;) = delete;
        SqlTransaction&amp; operator=(const SqlTransaction&amp;) = delete;
        SqlTransaction(SqlTransaction&amp;&amp;) = delete;

    private:
        std::shared_ptr&lt;sqlite::database&gt; db;
        bool finished = false;
    };


It's to be used like this:

SqlTransaction trans(db);
// work with db here, may throw if something goes wrong
trans.commit();
There's not a lot of code here to be reviewed, but I'll have a go.


A small efficiency gain is possible, by moving the db_ argument in the initializer list, rather than copying it:

SqlTransaction(std::shared_ptr&lt;sqlite::database&gt; db_)
  : db{std::move(db_)}
{ *db &lt;&lt; "begin;"; };

It's not necessary to delete the move constructor, as explicitly deleting the copy constructor prevents the move constructor being implicitly provided.  However, if you feel that doing so improves clarity, you should probably delete move assignment, too.
We should document that the class isn't thread-safe.  It's quite reasonable that we should use it from only one thread, but we need to be clear to our users about that.  Alternatively, we could make it thread-safe by making finished an std::atomic&lt;bool&gt; and using its test-and-set method, exchange().
Since rollback() tests finished, there's no need to duplicate that in the destructor - just call rollback() unconditionally.  It may be worth taking steps to avoid it throwing when called there - destructors that throw need to be handled with extreme care.

~SqlTransaction() { try { rollback(); } catch (...) { /* ignore */ } };



I have nothing specific to SQLite, as I've not used that library myself (I'm surprised it has to parse string commands, rather than having methods for those operations, though).