assignment operator swap idiom

I’ve been writing C++ since about 1986.  This post is more of a reminder than a tutorial.  One of the things I get junior C++ programmers to show me at interview, is writing a C++ assignment operator.

Problem

The C++ assignment operator is subtle, and very easy to get wrong.  If you are writing a “smart pointer” (which is neither) to manage reference counted objects, when the code explodes and blows your foot off the cause is actually several mountains away.

Note that this blog post is a restatement of the work of other brilliant people.

class example
{
private:
    int member;
public:
    ~example() { release(member)}
    example(const example &rhs) : member(copy(rhs.member)) { }
    example &operator=(const example &rhs)   
    {
         if (this != &rhs)
         {
             release(member);
             member = copy(rhs.member);
         }
         return *this;
    }
};

OK very small example, not actually a “smart pointer” but sufficient to demonstrate the solution.  This little example has some things to take note of:

  • The copy construtor’s code is duplicated in the assignment operator (bitrot: they will inevitably diverge over time).
  • The destructor’s code is duplicated in the assignment operator (bitrot: they will inevitabley diverge over time).

example::swap

The next step requires adding another method to the class, but one that is used extensively by the C++ standard library.

class example
{
private:
    // just the swap method for brevity
    void swap(example &rhs)
    {
        int temp = member;
        member = rhs.member;
        rhs.member = temp;
    }
};

Note that the swap is a shallow copy. If it were managing a reference counted object, there is no need to adjust the reference counts.

Code-Reuse

It is possible to the the swap method to have the compiler re-use the destructor code and re-use the copy constructor code.

class example
{
public:
    // just the assignment operator for brevity
    example &operator=(const example &rhs)    
    {
        example temp(rhs);
        temp.swap(*this);
        return *this;
    }
};

Things to note:

  • the copy constructor code is re-used,
  • the destructor code is re-used when destroying temp.
  • It works elegantly when faced with self assignment.

Just one more thing to note, if you are following the instance lifetimes carefully, it is possible to write this one line shorter, if the temporary is anonymous.

class example
{
    // just the assignment operator for brevity
    example &operator=(const example &rhs)    
    {
        example(rhs).swap(*this);
        return *this;
    }
};

But at the cost of possibly confusing later readers.

The Moral of Our Story

  1. Only destroy instance things in the destructor.  If you are destroying instance things in any other method, you are looking at a bug.
  2. If you find yourself writing your own “smart pointer” stop.  Use the ones from the Standard C++ library.  They are exception-proof and thread-proof.

Co-Maintainers Wanted

I am terminally ill, there exists a poorly defined window of time before my Open Source projects are involuntarily orphaned. It would be handy to use this window of time to transfer domain knowledge of my various Open Source projects to new maintainers.

The general issue is that sometimes people move on, and we often end up with Open Source projects without maintainers.  (If you know of an old answer to this old problem, that can be employed in this instance, I’d like to hear it.)

Here are the majority of my Open Source projects requiring a maintainer.

Git

The projects all use the Aegis DVCS.  The fact that the sources are not in Git may be a road-block for potential maintainers.  On the other hand, it may be enough to motivate a contributed refactoring that would allow Aegis to use a Git back-end.

I love geek humor:

You can move it to git over pmiller’s cold dead body? Might be a bit black.”

No, just a wee bit too soon.

I will have to a look at getting at least a copy of the trunk onto GitHub, for many of the projects.  If the code were already on GitHub then I am told that adoption would be repository transfer.

Tailor

Perhaps Tailor can help with this, if the necessary Aegis source-end were written. The  destination-end already exists.  If you know Tailor well, I would also like to hear from you.

From User to Maintainer

If you use a piece of Open Source software, it’s worth going further than just expecting someone else to keep maintaining it.  This how I have become a contributor to numerous projects (e.g. GNU Gettext). Many of my Open Source projects are aimed at software developers (e.g. SRecord).  Stepping up to maintainer should be relatively simple.

Seen from another perspective, only step up as maintainer for projects in a subject area you personally are interested in.  Don’t do it just because it’s a community-minded thing to do.  Projects that need them will get maintainers, eventually.

new lintian(1) .changes distribution check

I’m writing this up so I can find it again later, it will affect all of my open source projects (and a few closed source ones, too).

As of Ubunutal Quantal, lintian(1) has added a new test to the things it checks for  in the *.changes file.  It now checks that the Distribution: header contains a known distribution name. Continue reading

making assert(…) even more informative

If you are like me, you use assert all over the place. Even when compiled out, it serves are useful documentation as to what is going on (or what is supposed to be going on).  I recently learned another trick that I could have been using for the past 30 years, even when I first met C in the early 1980s. Continue reading

Priorities

I have dozens of open source software projects, in various stages of development.  I have three wood working projects waiting in the shed to be finished. I have phasmid populations studies I haven’t written up yet.  I have  four book reconstructions that I haven’t finished.

If you had 6 days to live, what would you work on? If you had  six months? Thirty years?

For me, my mind never stops.  It’s always coming up with ideas.  There is always software to write, there are always things to make with wood (and power tool therapy).  So, faced with a body that is failing, and a mind that isn’t, what would you work on?

The answer is: work on something you want to work on, you will anyway.  Work on something personally rewarding, or personally useful.  It turns out, the time limit is almost entirely irrelevant.

I’m working on a major release of Aegis, but also pecking away at other software projects, as brain capacity and haemoglobin permit.

I work on bug fixes and feature requests for my OSS projects if I feel like it; but that’s how OSS works.  Send me a patch, on the other hand, and I’ll integrate it the same days as I get it.

“Start a new project!” — Robert Collins.

Oops, yes, I did this, too.

Treatment

On the 11-Dec-2012 we start a third  chemotherapy sequence, this time using Bendamustine and Mabthera.  The list of known side effects of Bendamustine is very long.  What it will do to me is unknown, except that I will be allergic, and we will treat the symptoms and keep right on using the drug, because it’s my best bet, right now.  The treatment regimen has 2 days on and 26 days off, times 4 cycles.  In what looks like an emerging pattern, the Bendamustine isn’t on the PBS, so once again I am paying for a chemotherapy drug out of my own pocket.

We decided to start the chemotherapy now, rather than wait until after christmas.  My preference is to be doing, rather than waiting, even when doing will be confronting.  To procrastinate, to do nothing, is to choose to die.  I choose the option with at least a chance of living.

I accept this gift.

Gnome Shell: Not for me

Last week I posted about Ubuntu’s Unity desktop environment.  I have spent time since using the Gnome Shell for a similar amount of time.

  1. The two environments (Unity vs Gnome Shell) feel like different themes skinned over the same thing.  It is a complete mystery as to why the Unity folks felt the need to start their own project, rather than just make Gnome Shell theme-able, and then skin an Ubuntu theme over the top.
  2. The gnome shell uses considerably less CPU and GPU to render the environment (but still more than Gnome Classic No Effects).  The laptop is much quieter and quite noticeably less warm running Gnome Shell than when running Unity.
  3. The Unity interface is very “child’s plastic toy” themed, when compared to the slightly slicker Gnome Shell theme.  The notification pop-ups take a bit of getting used to, but tend to be nicer than notify-osd.
  4. The methods for choosing and switching between tasks and windows is equally revolting in both Unity and Gnome Shell.  The Gnome Classic task bars are still a clear ergonomic winner, for me.  All this whizzing around of window thumbnails is cool the first time, but it gets old real fast, by the second day it’s where the hell do I disable that? Yuck.
  5. The only good thing was that Gnome Shell uses the Metacity algorithm for window placement.

Just as with Unity, I can’t recommend Gnome Shell as a productive work environment.

 

Unity: Underwhelming

I have been looking at alternative graphical desk tops for Linux, given that Gnome Fallback Mode is going away soon.  In an effort to be fair, I try to use each one form more than 24 hours.

The machine I’m using is a Dell with an Nvidia graphcs card, with the Nvidea proprietary driver enabled.

Unity 3D

Without any customisation, or any apps running, Unity doing nothing eats 25% of both CPUs, and the GPU runs at 89C.  The laptop fan was maxed-out and constant — and loud.  With a bit of googling, I discovered that turning off CCSM->OpenGL->Sync-to-Vblank dropped the CPU usage markedly.  (WTF are they using a busy wait?!?)  The GPU was still running hot, though.

I find the unity Dash to be a very unpleasant interface.  I can’t browse to find what I want, I have to remember its name, instead, and then I have to type it.  Ugh.  The Dock down the left hand side looks like a Fischer Price toy computer.  There is no way to choose where you would like the dock (or you can use some random guy’s PPA to install a rotated-to-the-bottom dock).

The Alt-Tab application switcher is too fiddly to actually use.  One slip of the finger of the Alt key and it does some bullshit random thing you didn’t want.  And what ever you do, don’t Alt-Tab and then let both keys go (the thing I expected to do to have to app switcher persist until I had made my selection).  I find the app switcher inferior to the bottom panel in Gnome Fallback Mode.

Unity 2D

After 24 hours of constant fan noise, I switched to Unity 2D, foolishly assuming that the only difference would be the graphics rendering.  I’ve been using Unity 2D for several days.  I had assumed they used the same code for both, just with different graphical back ends.  Alas, no.

The window close/ min/ max buttons are on the right in Unity 3D, and on the left in Unity 2D.  The Alt-Tab application switcher is missing a couple of things that Unity 3D has, including “minimise all windows”, something I use often.  Neither 2D nor 3D have an “un-hide the windows just hidden” option.  This is probably the tip of the iceberg when it comes to unexpected inconsistencies between two desktop environments that, going by their names, create an expectation that they will be identical, except for some visual bling.

When using Unity 2D, the fan noise if far less than 3D, because it is running at its lowest speed.  The GPU is at 70C, which may explain why the fan never actually turns off.  For some alternative desktop environments, there is no fan noise, because the fan is off because nothing is happening.  My laptop used to be silent except when compiling (or a javascript in firefox went rogue).

Global Menu Bar

I dislike the global menu bar. I hated it on the Macintosh 20 years ago, and it turns out I still do. It may make sense for a mobile device with a touch screen and limited screen real estate, but it is absurd for a mouse desktop.  It is really tedious to have to mouse 3/4 of the screen in order to get to the app’s menus; this is not a good use of my time.  Why is it that in order to turn off the global menu bar, I have to actually uninstall the software package that implements it?  Why is this not a simple on/off preference?

The skinny scroll bar is also unpleasant.  It is too thin, too fiddly, and PITA when the scroll bar is on the right hand edge of the screen. Why is it that to turn off the stupid skinny scroll bar I have to actually uninstall the software package that implements it?  Why is this not a simple on/off preference?

Window Placement

The unity new-window placement algorithm leaves much to be desired.  It frequently puts new windows in the top-left corner, even when there is more than enough clear space for the new window elsewhere.  (Or is it an admission that anywhere else on the screen makes the global menu a pita?)

I hadn’t noticed just how much I use and like Metacity’s slightly sticky window edges, so than when moving a window, it briefly sticks to window and screen margins, allowing easy alignment without sub-pixel accurate mouse movements.  The absence of this feature in Unity, I discovered, is quite frustrating.

Why can’t I drag-n-drop windows in the workspace switcher?

Another thing that trips me up constantly is the “maximum gesture”.  If you click-and-hold on a window title bar, and then move right rapidly, this maximises the window.  As you can imagine, when you want your new window anywhere other than the top-left corner, you are going to do this.  Grumpiness ensues.

Gnome Panel

One of the things I missed in Unity are the top and bottom panels I have been using in Metacity.  I tried running gnome-panel anyway, and it mostly works.  The bottom bar is back as usual, and the top bar is alternating between Unity and Gnome Panel, but switching the two is a matter of mouse gestures, no clicking, no typing.

Conclusion

I could not recommend Unity 2D or Unity 3D to anyone.  I will continue my search for a new desktop environment for Linux, but in the present winner is Gnome Fallback Mode combined with Metacity.