beatwaves.net

C++

Emulating special constructors for const objects with a wapper class in C++

I spent a few hours today figuring out how to make the cleanest possible const-correct code for a class that contains a reference or pointer member, whose constness is protected by accessor functions. Here is an example class:

  1. class Example
  2. {
  3. public:
  4.     Example (Data & data) : data (data) {}
  5.  
  6.     Data &       data()       { return data; }
  7.     Data const & data() const { return data; }
  8.  
  9.    /* More stuff here in a real situation ... */
  10.  
  11. private:
  12.     Data & data;
  13.    /* More stuff here in a real situation ... */
  14. };

The problem with this class arises when you want to instantiate a const Example from a const Data object. The constructor wanẗ́s a non-const reference in any case, and C++ does not support special constructors for const objects. The cleanest solution I came up with, was making a ConstExample class (similar to const_iterator in STL). I ended up implementing a simple wrapper with a bunch of overridden operators:

  1. class ConstExample
  2. {
  3. public:
  4.     ConstExample (Data const & data)
  5.       : example (const_cast<Data &>(data)) {}
  6.  
  7.     inline operator Example const & () { return example; }
  8.     inline Example const * operator& () { return &example; }
  9.     inline Example const * operator-> () { return &example; }
  10.     inline Example const & operator() () { return example; }
  11.  
  12. private:
  13.     Example example;
  14. };
  • A const_cast is involved, but that is rather inevitable because of the limitations of C++
  • The first two operators make it possible to pass the object as a const reference or pointer to an Example object.
  • The third and fourth make it possible to call const functions (or reference members) of Example. You'll probably want to use only one of these, if any. In my case, the object will mostly just be passed to functions as a reference.

This might not be the best way to do things in all cases. Sometimes splitting the main class into a const base class, which is inherited by a non-const class might be a better solution (e.g. Symbians descriptor classes). It all depends on the use case and semantics of const.

The environment I'm using this pattern in, has separate overrides for functions that handle non-const and const data. The const data often needs to be copied for processing, while the non-const version can save memory by doing in-place processing. Also, most of the time const objects are constructed from non-const data, only to tell others that the data should not be changed. So, in my case this pattern is very transparent.

I also considered a static factory function (i.e. Example const e = Example::Const (data);) and some kind of solution using template specializations, but ended up using a wrapper class instead.

If you know of some other solution (or a very clean template-based solution) please leave a comment!

Progress with Ardour session merger

The last few couple of days I've been working on my Ardour session merger, which will hopefully eventually be a part of Ardour. I got a lot done, but much still has to be done.

I've never really liked GUI-programing, and gtkmm doesn't seem like too much fun either. Nevertheless, I got a basic implementation done, which is capable of importing locations from a session file to the currently open Ardour session.

See the project page for a screen shot and more!

System architecture

Main functionality

The session merger is capable of importing parts from one Ardour session to another. A 'part' is anything defined in the session file (XML). This includes regions, tracks, settings etc. The merger reads a session file and imports parts of it into an already open session according to the users selections.

Element classes

The program shall be made extensible by using a polymorphic element class representing a certain type of XML node or some XML attribute. Different element classes can be easily added without changing GUI code.

Ardour session merger

This page has material related to an ongoing project, a session merger session element importer for Ardour.

Current status

2009-05-16
Locations, Regions, Playlists, Tracks and the tempo map can be imported. The code is still in 3.0 SVN. It has not been tested much and the UI could still use some love.

2008-09-26
Locations, Regions, Playlists and the tempo map can be imported. The session merging code is part of Ardours 3.0 SVN branch as of revision 3805. GUI still needs some work

Screen shots

Tags:

Crumbled Earth

Crumbled Earth is a two player tank game created as a school project work. It was written by a group of three, including myself. It is written in C++, and it uses ClanLib heavily. ClanLib is a cross platform C++ toolkit library with a primary focus on games. I was responsible for coding the sound engine, GUI, player input handling and random terrain generator.