Cpp

Container changes in C++11

The recently approved C++11 standard brings a lot of welcome changes to C++ that modernize the language a little bit. Among the many changes, we find that containers have received some special love.

Initialization

C++ was long behind modern languages when it came to initializing containers. While you could do

[cpp]int a[] = {1, 2, 3};[/cpp]

for simple arrays, things tended to get more verbose for more complex containers:

[cpp]
vector v;
v.push_back(“One”);
v.push_back(“Two”);
v.push_back(“Three”);
[/cpp]

C++11 has introduced an easier, simpler way to initialize this:

[cpp]
vector v = {“One”, “Two”, “Three”};
[/cpp]

The effects of the changes are even better for things like maps, which could get cumbersome quickly:

[cpp]
map<string, vector > m;
vector v1;
v1.push_back(“A”);
v1.push_back(“B”);
v1.push_back(“C”);

vector v2;
v2.push_back(“A”);
v2.push_back(“B”);
v2.push_back(“C”);

m[“One”] = v1;
m[“Two”] = v2;
[/cpp]

This can now be expressed as:

[cpp]
map<string, vector> m = One,

                             {"Two", {"Z", "Y", "X"}}};

[/cpp]

Much simpler and in line with most modern languages. As an aside, there’s another change in C++11 that would be easy to miss in the code above. The declaration

[cpp]map<string, vector> m;[/cpp]

was illegal until now due to » always being evaluated to the right-shift operator; a space would always be required, like

[cpp]map<string, vector > m[/cpp]

No longer the case.

Iterating

Iterating through containers was also inconvenient. Iterating the simple vector v above:

[cpp]
for (vector::iterator i = v.begin();

 i != v.end(); i++)
cout << i << endl;[/cpp]

Modern languages have long had some foreach equivalent that allowed us easier ways to iterate through these structures without having to explicitly worry about iterators types. C++11 is finally catching up:

[cpp]
for (string s : v)

cout << s << endl;

[/cpp]

As well, C++11 brings in a new keyword, auto, that will evaluate to a type in compile-type. So instead of

[cpp]
for (map<string, vector >::iterator i = m.begin();

 i != m.end(); i++) {

[/cpp]

we can now write

[cpp]
for (auto i = m.begin(); i != m.end(); i++) {
[/cpp]

and auto will evaluate to map<string, vector>::iterator.

Combining these changes, we move from the horrendous

[cpp]
for (map<string, vector >::iterator i = m.begin();

 i != m.end(); i++)
for (vector<string>::iterator j = i->second.begin();
     j != i->second.end(); j++)
    cout << i->first << ': ' << *j << endl;

[/cpp]

to the much simpler

[cpp]
for (auto i : m)

for (auto j : i.second)
    cout << i.first << ': ' << j << endl;

[/cpp]

Not bad.

C++11 support varies a lot from compiler to compiler, but all of the changes above are already supported in the latest versions of GCC, LLVM, and MSVC compilers.

Const Does Not Mean Concurrent

A cache lookup crashed under load today even though every worker called a const method. That sentence sounds reassuring only if const is mistaken for a locking primitive.

The method updated a mutable cache:

QImage ImageStore::image(const QString &key) const
{
    if (!m_cache.contains(key))
        m_cache.insert(key, loadImage(key));
    return m_cache.value(key);
}

const prevents ordinary modification through the public type. It says nothing about simultaneous calls, and mutable explicitly allows internal state to change. Two processors can both inspect and modify the cache, corrupting its internal bookkeeping.

I first added a mutex around the whole operation. That was correct but serialised disk loading, so unrelated images waited behind one slow file. The improved version checks under lock, loads outside it, then locks again to publish:

QImage ImageStore::image(const QString &key) const
{
    m_mutex.lock();
    if (m_cache.contains(key)) {
        QImage image = m_cache.value(key);
        m_mutex.unlock();
        return image;
    }
    m_mutex.unlock();

    QImage image = loadImage(key);

    m_mutex.lock();
    if (!m_cache.contains(key))
        m_cache.insert(key, image);
    else
        image = m_cache.value(key);
    m_mutex.unlock();
    return image;
}

Duplicate loading is possible, but publication is safe and the common cached path is short. For expensive loads I might track in-progress keys with a wait condition; that complexity needs measurements first.

Implicitly shared Qt values make returning an image cheap in the usual case, but they do not make shared storage safe for concurrent mutation. Copy-on-write protects value semantics, not arbitrary access patterns.

The lock itself belongs beside the state it protects. Passing the cache to helper code without the mutex invites a second access path that quietly ignores the rule. I am documenting the invariant as “all cache lookup and publication occurs while holding m_mutex,” then checking each method against that sentence.

I prefer immutable inputs and per-job results when using several cores. Shared caches should be small, explicitly locked, and treated as an optimisation rather than the foundation of correctness. The caveat is memory and copying: some data is too large to duplicate, so careful shared ownership remains necessary.

The failure appeared only on the dual-core machine and only after several minutes. That does not make it a rare bug. It makes the single-core test machine an excellent accomplice.

What the Desktop Taught Me This Year

I spent much of this year fixing things that I first tried to solve at the wrong layer. A missing button event sent me into desktop settings. A wandering disk name produced a worse shell script. A driver race invited more logging. My instincts have been very energetic, if not consistently useful.

The better method is to follow the mechanism. Kernel devices appear through the device model and sysfs; udev applies naming policy. Input travels from the kernel through X.Org to applications. Qt objects have explicit parent ownership. Deferred kernel work has context and lifetime rules. Git history is a graph of objects, not a remote folder with ceremony.

KDE 3.5 ties the user-facing side together with unusual steadiness. Its maturity is not one clever feature but the accumulated reliability of applications, libraries, and conventions.

My practical conclusion for the year is to identify the boundary before editing the configuration or code. Ask what layer owns the decision, what evidence crosses that boundary, and what lifetime the data has. Then make one change and test it.

This sounds obvious when written in December. In February it apparently required an oops. Education remains committed to memorable examples.

Porting a Qt 3 Dialog to Qt 4

Qt 4.0 is out, so I chose a small Qt 3.3 dialog as a porting exercise. “Small” was important. Porting an entire application before understanding one dialog is how weekends acquire stack traces.

My first attempt was purely mechanical: change includes until the compiler became quiet. It became quieter, but not helpful. Qt 4 reorganizes classes into modules, changes parts of the collection and painting APIs, and separates concerns that older code often mixed together. A successful compile would not prove that I had preserved ownership, event behavior, or rendering.

I started again by writing down the dialog’s behavior. It displays a list of files, accepts a selection, paints a small preview, and emits a result. That description gave me four pieces to port and test independently instead of one pile of compiler diagnostics.

The build was the first useful boundary. The project now names the Qt modules it uses rather than assuming one enormous library. Includes should name the class headers actually required. This exposed accidental dependencies that had been hidden by broad headers in the old source.

Collections needed care, but not cleverness. I resisted making a grand compatibility wrapper around every changed type. This application has one current port, not a treaty organization. At each call site I checked iterator behavior, copying, and whether Qt or standard C++ ownership applied.

The list view was the largest conceptual change. Old code tended to let a widget store items and presentation behavior together. Qt 4’s item-view approach makes the model explicit. My naive response was to force the old item manipulation into the new widget. The cleaner solution was to expose the file data through a model and let the view handle selection and display.

That split initially looked like extra ceremony. It paid for itself when I wanted to sort the view without rearranging the underlying file objects. Presentation order and data ownership are not the same thing, and the API now encourages me to admit it.

Painting also demanded attention. The preview had drawn directly in a way that relied on Qt 3 behavior. In Qt 4 I kept custom drawing inside the paint event, used the supplied paint device, and treated coordinates and clipping as part of the callback contract.

void Preview::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setClipRegion(event->region());
    painter.drawPixmap(0, 0, previewPixmap);
}

This is deliberately plain. Caching the pixmap avoids repeating file work during repainting, while the widget remains responsible for drawing itself when requested. Calling painting code from arbitrary places had seemed direct in the old version; it was actually borrowing assumptions from the event loop.

Object ownership survived mostly intact because parent-child relationships still provide a clear lifetime for QObject instances. I nevertheless checked every allocation. A port is a good time to discover that an object was parented only by luck or that two cleanup paths both believed they were in charge.

Signals and slots remain familiar, which made them easy to overlook. I checked each important connect() and exercised the dialog through the keyboard as well as the mouse. Compilation catches C++ type errors; it does not guarantee that a runtime signal signature agrees with its slot.

I kept the Qt 3 version running beside the port and compared behavior with the same small directory. Selection changes, empty lists, unreadable files, cancellation, and repeated opening all went on a short test sheet. The empty case found a stale selection pointer that the happy path had concealed.

The temptation during a port is to redesign everything disliked in the old code. I limited changes to those required by the new APIs or needed to make the behavior testable. Otherwise a regression becomes impossible to classify: was it introduced by Qt 4, the port, or my spontaneous improvement campaign?

My early opinion is that Qt 4 asks C++ applications to make more structure explicit, particularly around data and views. That can feel verbose when porting a tiny widget, but it scales better than teaching every widget to own, sort, and display its own private universe.

The useful conclusion is to port by responsibility, not by compiler error. Establish a build boundary, preserve observable behavior, understand the replacement mechanism, and test ownership and callbacks. The compiler is an excellent assistant, but it has never used the dialog and is therefore a poor product manager.

QObject Ownership Is Not Garbage Collection

I found a leak in a small Qt 3.3 dialog and responded by deleting every child widget in the destructor. Then I noticed that the widgets already had the dialog as their parent. My heroic cleanup was redundant; the actual leak was an object with no parent at all.

Qt’s object trees are straightforward once I stop pretending they are magic. A QObject with a parent joins that parent’s child list. Destroying the parent destroys its children. Top-level objects and objects without parents remain my responsibility.

My useful check is now mechanical. At construction, I ask who owns each allocation. If the answer is a parent object, I do not delete it separately. If there is no parent, I give the lifetime an explicit home in C++ code. Layouts arrange widgets; they do not replace ownership reasoning.

QLabel *label = new QLabel(tr("Status"), this);

Here this is the relevant part, not new. The parent makes the intended lifetime visible and ties cleanup to the dialog.

This is not garbage collection. Qt does not discover arbitrary unreachable C++ objects, and a parent cannot rescue a dangling pointer used after destruction. It is a disciplined ownership convention layered over C++.

The conclusion is pleasantly small: establish one owner and make it obvious at construction. My destructor became shorter, which is about the nicest possible result of debugging C++ memory management.