hackergotchi
Tales from a phasmatodean man

Peter Miller is a senior software developer with over 30 years on embedded systems. He has experience on a variety of platforms and is renowned for his focus on effective software testing practises. He was one of the the original authors of the now universally used gettext internationalization infrastructure. Lately he has been writing a library to better “explain” error messages coming from the Linux kernel's various system calls.

Contact...

Twitter @PeterMillerAus

Google Plus +Peter Miller

Email 0x70405E10

RSS Feed /pmiller

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.

Feelings of Fraud

My transfusion schedule cuts across many of the other patients’ chemo schedules.  We get to talking, and a bit of a theme has emerged.

One of my friends has inoperable liver cancer, but most of the time she looks great, she’s still driving herself to chemo and oncologist appointments.  She lives with  the feeling that eventually some-one will jump up and yell to the world, “hey everyone, she’s’ a fraud”.

Often, when friends visit, they exclaim “wow, you look good”.  Every time someone says this, I feel like I should be out there getting a job.  I have managed to do some small and not so small, woodwork projects.  The logic goes like this, if I’m well enough to do woodwork, I can’t be so sick.  If you can make a big honking table, you can’t be terminally ill.  Eventually I worked out that this exclamation is relative to the speaker.  And usually translates to “wow, you look better than I prepared myself to see.”

Two short notes; I have to sleep or at least rest for two hours for each hour in the workshop.

Note two, without minimising the significance of the issue for my female IT colleagues, this bears a striking resemblance to Impostor Syndrome.

Developers are bad for build systems

It has often been observed that developers are the enemy of build systems. It is a rare person who actually knows how they work. (The variety of OSS build system available now fall into two main categories: (1) make, cook, and jam (et al) work backwards from the outputs; and (2) automake, scons, waf (et al) that work forward from the sources. I tend to blend them, myself, as circumstances require.

One method I use to keep developers away from my build systems is to

  1. Ask the version control system for a definitive list of primary source files.
  2. Using heuristics, generate a Makefile or a Makefile.am file (etc).  Non-recursive, of course.
  3. Make sure the (generated) Makefile knows how to update the Makefile.

The great thing with this method is that when users add a new file to a change set (“svn add”, or similar) the next build will automatically notice it, and rewrite the Makefile (or whatever) and then build your new file.  You can approximate this technique using find(1), and filtering out all build products (heuristically).

Now, this isn’t simple, because users also structure source trees in weird and wonderful ways. But you can depend on some things, like a directory called “lib” almost certainly contains source files to be compiled and linked into a library.

Another pattern is to treat every .c or .cpp file in the “src” directory as a command to be compiled and linked, probably to including that common library of functions. (Except when a some of files under “src” should be a common library, and then you have to look in the source files, looking for the main() function, to find programs to build.)  Don’t bike shed the concept, just hack something that works, and then you can improve it later, in light of experience, and possibly some yak shaving much later for entertainment.

My projects tend to be larger than that, and I use a heuristic that every directory that contains main.c or main.cpp (etc) should have all of it source files compiled and linked into the one program, and also to that common library of functions, probably.  If a program has a name starting with “test_” is is built (for use by automated tests) but not installed.

The point is to manipulate the shape of your source directory tree so that a relatively simple program can generate the build system from the definitive list of primary source files.  For example: you can easily see the mapping from the list of primary source files to the Makfile.am contents, it’s almost 1:1.

Now that users don’t need to edit the Makefile, they don’t need to fsck it up, either.

Also, I always build executables into a single directory called “bin”. It makes it very easy to set the PATH when running automated tests.

The Not-So-Gentle Answer: 10. Perceptions of Strength

For many months now, I have been confused when people tell me that I am a strong person. Some people have even described me as the strongest person they know. This is their perception, and I can’t and shouldn’t argue with them. This blog post is the process of me understanding that perception of me by other people. Continue reading


Material on this site copyright © 2002-2013 Operational Dynamics Consulting Pty Ltd, unless otherwise noted. All rights reserved. Not for redistribution or attribution without permission in writing. All times UTC

We make this service available to our staff and colleagues in order to promote the discourse of ideas especially as relates to the development of Open Source worldwide. Blog entries on this site, however, are the musings of the authors as individuals and do not represent the views of Operational Dynamics