[cppx] 3 ways to mix in a generic cloning implementation

To clone an object is to create a dynamically allocated copy of the object, of the same dynamic type, generally without knowing the exact dynamic type. The common way to do that is a virtual method, e.g. called clone, that simply invokes the type’s copy constructor. And the main problem with cloning in C++ is: how to reduce the extreme redundancy of zillions of essentially identical clone methods everywhere?

Background: the basic “raw” C++ cloning idiom

Since a clone method corresponds to a copy constructor there are other possible polymorphic instantiation operations that can be implemented as virtual methods and that correspond to other constructors. E.g. the C++ FAQ item that discusses cloning additionally includes discussion of a create method that corresponds to a default constructor; it offers a default instance of the dynamic type. But I’ve never needed that.

Perhaps the most obvious use of cloning is in a diagram editor where the user can copy any shape in a diagram, and the corresponding code needs to copy a shape object without knowing its dynamic type (circle, cloud symbol, whatever, the code shouldn’t have to know). And perhaps less obvious, where you logically need to propagate a C++ exception up through C code you will generally be in UB-land, leaking resources and setting inconsistent states, if you just do that directly. And one C++98 solution is then to clone the exception before returning up through the C code, and rethrow, via a virtual thrower method, in the C++ calling code.

For the exception propagation use case it doesn’t really matter what statically known type the clone method produces; a generic Exception* will do. But in other cases the caller of clone may know that the object to be cloned is of type Foo, say, not just a generic Object, although not knowing exactly which kind of Foo, and then for that code you may wish to invoke Foo-specific methods on the clone without having to downcast the clone result. Hence, ideally clone should produce a raw or smart pointer of as specific a type as possible, like:

“Raw” cloning & exception propagation, complete example:

#include <iostream>
#include <stdexcept>    // std::runtime_error, std::exception
#include <memory>       // std::auto_ptr
#include <assert.h>     // assert
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE

class Exception
    : public std::runtime_error
{
public:
    typedef std::runtime_error      Base;

    Exception( char const* s )
        : Base( s )
    {}

    virtual Exception* clone() const
    {
        return new Exception( *this );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

class FooException
    : public Exception
{
public:
    typedef Exception               Base;

    FooException( char const* s )
        : Base( s )
    {}

    virtual FooException* clone() const
    {
        return new FooException( *this );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

class BarException
    : public Exception
{
public:
    typedef Exception               Base;

    BarException( char const* s )
        : Base( s )
    {}

    virtual BarException* clone() const
    {
        return new BarException( *this );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

namespace global {
    Exception*  pCurrentX       = 0;
}    // namespace global

void rethrowCurrentIfAny()
{
    if( global::pCurrentX != 0 )
    {
        Exception* const    pX  = global::pCurrentX;
        global::pCurrentX = 0;
        std::auto_ptr< Exception >( pX )->throwSelf();
    }
}

void codeCalledByCallback()
{
    throw FooException( "A detailed explanation of what failed" );
}

extern "C" int callbackFunc()
{
    try
    {
        codeCalledByCallback();
        return true;
    }
    catch( Exception const& x )
    {
        global::pCurrentX = x.clone();
    }
    catch( std::exception const& x )
    {
        global::pCurrentX = new Exception( x.what() );
    }
    catch( ... )
    {
        global::pCurrentX = new Exception( "An unknown exception" );
    }
    return false;
}

extern "C" int someApiFunc( int (*f)() )
{
    int     result;
    char*   pBuffer     = (char*) malloc( 100000 );
    result = f();
    free( pBuffer );
    return result;
}

void doSomething()
{
    assert( global::pCurrentX == 0 );
    if( !someApiFunc( &callbackFunc ) )
    {
        rethrowCurrentIfAny();
        throw Exception( "someApiFunc failed" );    // Generic fallback.
    }
}

int main()
{
    try
    {
        doSomething();
        return EXIT_SUCCESS;
    }
    catch( FooException const& x )
    {
        std::cerr << "!Foo -- " << x.what() << std::endl;
    }
    catch( std::exception const& x )
    {
        std::cerr << "!" << x.what() << std::endl;
    }
    return EXIT_FAILURE;
}

Just for completeness:

  • The Exception destructor needs to be virtual in order to support delete of an Exception whose dynamic type may be some derived class such as FooException. The destructor is virtual because Exception inherits from std::runtime_error, which has a virtual destructor. This makes the automatically generated Exception destructor virtual.
  • The clone method needs to be virtual in order to support cloning where you don’t know the exact dynamic type.
  • In class Exception the result type of clone is Exception*, while in the derived class FooException the clone result type is FooException*. The latter is still an override of the former. It’s called a covariant result type, a result type that varies in specificity in the same way (co) as your choice of which class to look at.
  • The three apparently identical throwThis implementations are necessary. It’s only at the source code level that they’re identical, i.e., they are only textually identical. Like the nearly textually identical clone implementations they deal with different statically known types, and are translated to slightly different machine code routines.
  • This example code is by design not thread safe (I just kept it simple).

How to implement covariance with a smart pointer result type

C++ does not support covariance or contravariance (the opposite) for ordinary arguments, mainly because in C++ there is nothing that tells the compiler whether a pointer or reference argument carries data in to the function, out of the function or both ways. But the result of a function is known to be pure “out”, and so for this special case C++ can support covariance, and does. However, that support is limited to raw pointer and reference result types.

With a smart pointer clone result one must therefore implement the covariance oneself.

It can be done as follows:

Covariant smart pointer function results, complete example:

#include <iostream>
#include <stdexcept>    // std::runtime_error, std::exception
#include <memory>       // std::auto_ptr
#include <assert.h>     // assert
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE

class Exception
    : public std::runtime_error
{
protected:
    virtual Exception* virtualClone() const
    {
        return new Exception( *this );
    }

public:
    typedef std::runtime_error      Base;

    Exception( char const* s )
        : Base( s )
    {}

    std::auto_ptr< Exception > clone() const
    {
        return std::auto_ptr< Exception >( virtualClone() );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

class FooException
    : public Exception
{
protected:
    virtual FooException* virtualClone() const
    {
        return new FooException( *this );
    }

public:
    typedef Exception               Base;

    FooException( char const* s )
        : Base( s )
    {}

    std::auto_ptr< FooException > clone() const
    {
        return std::auto_ptr< FooException >( virtualClone() );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

class BarException
    : public Exception
{
protected:
    virtual BarException* virtualClone() const
    {
        return new BarException( *this );
    }

public:
    typedef Exception               Base;

    BarException( char const* s )
        : Base( s )
    {}

    std::auto_ptr< BarException > clone() const
    {
        return std::auto_ptr< BarException >( virtualClone() );
    }

    virtual bool throwSelf() const
    {
        throw *this;
    }
};

namespace global {
    // The std::auto_ptr wrapping here is for *convenience*, not for safety.
    std::auto_ptr< Exception>   pCurrentX;
}    // namespace global

void rethrowCurrentIfAny()
{
    if( global::pCurrentX.get() != 0 )
    {
        std::auto_ptr< Exception >( global::pCurrentX )->throwSelf();
    }
}

void codeCalledByCallback()
{
    throw FooException( "A detailed explanation of what failed" );
}

extern "C" int callbackFunc()
{
    try
    {
        codeCalledByCallback();
        return true;
    }
    catch( Exception const& x )
    {
        global::pCurrentX = x.clone();
    }
    catch( std::exception const& x )
    {
        global::pCurrentX.reset( new Exception( x.what() ) );
    }
    catch( ... )
    {
        global::pCurrentX.reset( new Exception( "An unknown exception" ) );
    }
    return false;
}

extern "C" int someApiFunc( int (*f)() )
{
    int     result;
    char*   pBuffer     = (char*) malloc( 100000 );
    result = f();
    free( pBuffer );
    return result;
}

void doSomething()
{
    assert( global::pCurrentX.get() == 0 );
    if( !someApiFunc( &callbackFunc ) )
    {
        rethrowCurrentIfAny();
        throw Exception( "someApiFunc failed" );    // Generic fallback.
    }
}

int main()
{
    try
    {
        doSomething();
        return EXIT_SUCCESS;
    }
    catch( FooException const& x )
    {
        std::cerr << "!Foo -- " << x.what() << std::endl;
    }
    catch( std::exception const& x )
    {
        std::cerr << "!" << x.what() << std::endl;
    }
    return EXIT_FAILURE;
}

Overview: three ways to centralize the implementation

No matter whether the static result type of clone is covariant or not, the implementation of clone involves a covariant type. And this means that each and every class in hierarchy where the root class supports cloning, must be outfitted with its own clone implementation. Doing that manually, as above, yields quite a lot of redundant code!

Since each implementation is class-specific a centralized generic implementation must be either a template or a macro.

Mixing in a templated implementation can be done in two main ways, so in all there are three main ways to mix in a generic clone (or for that matter e.g. throwSelf) implementation:

  • A templated implementation mixed in via (what I call) sideways inheritance. For this it’s necessary to leverage dominance in virtual inheritance. Although that may sound a bit scary it is in fact rather conventional, e.g. it corresponds directly to inheritance of an implementation of an interface in Java, but virtual inheritance carries some runtime overhead.
  • A templated implementation mixed in as (what I call) a middleman base class. For this it’s in general necessary to do constructor argument forwarding, which is not directly supported in C++98. Happily some practical C++98 argument forwarding solutions exist, and I’ve written about one such in an earlier posting.
  • A macro-based implementation mixed in by a macro call placed in each class declaration. This is simple and direct, grokkable by all?, and it is how the cppx library cloning support works. The downside is – macros…

I chose the macro solution for cppx because it’s simple and robust. It’s the KISS principle: Keep It Simple, Stupid! :-) However, for completeness I here first exemplify and discuss the two template-based ways.

It would be really nice if C++ had direct language support for this kind of thing. If you could define in some base class a covariant method implementation, and have it automatically generated in derived classes. Alas, there is no such support.

Way #1: Mix-in via sideways inheritance

The concept of C++ dominance is a bit hard to pin down, but essentially what would have been an ambiguous name reference with ordinary multiple inheritance, can be well-defined with virtual inheritance. If V is a virtual base class then a name defined in a class derived from V wins over the same name in V. I tried to find this in the standard but alas, even though I vaguely remember finding it several times before, no dice: it’s apparently well hidden.

One way to think of it is that it provides the same inherit-an-implementation-of-an-interface functionality as in Java. The names in the implementation class dominate those in the interface. That is, when the interface is a virtual base class, as it generally should be.

The main idea here is to have main inheritance chain for mixin user classes, and a parallel inheritance chain of virtual base to-be-mixed-in classes. Using virtual inheritance lets dominance come into play, so that instead of resulting in ambiguities the functionality is sort of fused into the main chain. :-) It can look like this (oh, the word “like”: no, this is real code!):

File [cloning_sideways_mixin.h], complete example:

#ifndef CLONING_SIDEWAYS_MIXIN
#define CLONING_SIDEWAYS_MIXIN

//---------------------------------------- Dependencies:

#include <typeinfo>
#include <memory>       // std::auto_ptr
#include <assert.h>     // assert

//---------------------------------------- Interface:

class NoBaseClass {};

template< class Derived, class BaseOfDerived >
class CloningOf;

template<
    class Derived, class BaseOfDerived,
    class VirtualCloneResult,
    class ImplBase
    >
class CloningOfImpl
    : public virtual ImplBase
{
protected:
    virtual VirtualCloneResult* virtualClone() const
    {
        assert( typeid( *this ) == typeid( Derived ) );

        Derived const&  self    = dynamic_cast< Derived const& >( *this );
        return new Derived( self );
    }

public:
    typedef CloningOf< Derived, BaseOfDerived >     CloningImpl;

    std::auto_ptr< Derived > clone() const
    {
        return std::auto_ptr< Derived >(
            static_cast< Derived* >( virtualClone() )
            );
    }
};

template< class Derived, class BaseOfDerived >
class CloningOf
    : public CloningOfImpl<
        Derived,
        BaseOfDerived,
        typename BaseOfDerived::CloneableRootClass,
        typename BaseOfDerived::CloningImpl
        >
{};

template< class Derived >
class CloningOf< Derived, NoBaseClass >
    : public CloningOfImpl<
        Derived,
        NoBaseClass,
        Derived,
        NoBaseClass
        >
{
public:
    typedef Derived     CloneableRootClass;
};

#endif

One main thing to note is that a client code class must inherit virtually from CloningOf, and that this in turn necessitates a dynamic_cast instead of a static_cast in virtualClone, even though from our whole-program perspective it’s known that the types are related via inheritance. And this dynamic_cast can be a tad inefficient, although in the context of dynamic allocation that particular inefficiency is perhaps marginal. I guess the dynamic_cast can be avoided by introducing additional complexity (as I recall that complexity was one main reason why I chose to go with a macro-based scheme for the cppx library).

Actual usage in the same example program as before can look like this:

Example of mixing in a sideways inheritance clone implementation:

#include <stdexcept>    // std::runtime_error, std::exception
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE
#include "cloning_sideways_mixin.h"

class Exception
    : public std::runtime_error
    , public virtual CloningOf< Exception, NoBaseClass >
{
public:
    typedef std::runtime_error  Base;

    Exception( char const* s ): Base( s ) {}
    virtual bool throwSelf() const  { throw *this; }
};

class FooException
    : public Exception
    , public virtual CloningOf< FooException, Exception >
{
public:
    typedef Exception   Base;

    FooException( char const* s ): Base( s ) {}
    virtual bool throwSelf() const { throw *this; }
};

class BarException
    : public Exception
    , public virtual CloningOf< BarException, Exception >
{
public:
    typedef Exception   Base;

    BarException( char const* s ): Base( s ) {}
    virtual bool throwSelf() const { throw *this; }
};

//... The rest as before.

Now if you’re like me you’re probably wondering whether a call to clone will need to be disambiguated, and if not, whether it will produce a correct as-specialized-as-possible statically covariant result. In fact it works just fine, with g++ and MSVC at least. E.g., the call …

std::auto_ptr< FooException > p( x.clone() );

… where x is of type FooException, compiles just fine (except for MSVC sillywarnings, of course), and works just fine.

However, as mentioned I’d be hard pressed to prove that this code is standard-conforming, since – perhaps I’m blind on both eyes – I can’t find this in the standard.

Way #2: Mix-in via a middleman base class

What I call a middleman base class is just a templated class inserted into the inheritance between Derived and Base. When Base has one or more constructors in addition to a default constructor and copy constructor, this necessitates argument forwarding from Derived to Base, via the middleman class. Happily that’s easy to do in a general way, using e.g. my cppx::ConstructorArgForwarder class (which itself is a middleman base class, but never mind):

File [cloning_middleman_mixin.h], complete example:

#ifndef CLONING_MIDDLEMAN_MIXIN
#define CLONING_MIDDLEMAN_MIXIN

//---------------------------------------- Dependencies:

#include <progrock/cppx/arguments/ConstructorArgForwarder.h>

#include <typeinfo>
#include <memory>       // std::auto_ptr
#include <assert.h>     // assert

//---------------------------------------- Interface:

template< class Derived, class Base >
class WithCloningOf
    : public progrock::cppx::ConstructorArgForwarder< Base >
{
protected:
    virtual WithCloningOf* virtualClone() const
    {
        return new Derived( *static_cast< Derived const* >( this ) );
    }

public:
    template< class ArgPack >
    WithCloningOf( ArgPack const& args )
        : progrock::cppx::ConstructorArgForwarder< Base >( args )
    {}

    std::auto_ptr< Derived > clone() const
    {
        return std::auto_ptr< Derived >(
            static_cast< Derived* >( virtualClone() )
            );
    }
};

#endif

Did I forget an assert here? Yes, I did. But no matter. <g/>

Actual usage in the same example program as before can look like this:

Example of mixing in a middleman base class clone implementation:

#include "cloning_middleman_mixin.h"
namespace cppx = progrock::cppx;

#include <iostream>
#include <stdexcept>    // std::runtime_error, std::exception
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE

class Exception
    : public WithCloningOf< Exception, std::runtime_error >
{
public:
    typedef WithCloningOf< Exception, std::runtime_error >  Base;

    Exception( char const* s ): Base( cppx::args( s ) ) {}
    virtual bool throwSelf() const { throw *this; }
};

class FooException
    : public WithCloningOf< FooException, Exception >
{
public:
    typedef WithCloningOf< FooException, Exception >    Base;

    FooException( char const* s ): Base( cppx::args( s ) ) {}
    virtual bool throwSelf() const { throw *this; }
};

class BarException
    : public WithCloningOf< BarException, Exception >
{
public:
    typedef WithCloningOf< BarException, Exception >    Base;

    BarException( char const* s ): Base( cppx::args( s ) ) {}
    virtual bool throwSelf() const { throw *this; }
};

//... The rest as before.

Hm, it’s not as bad as I thought it would be. I’m not sure why I didn’t choose this solution for the cppx library, instead of the macro approach. But anyway: herewith, the macro!

Way #3: Mix-in via a macro (the cppx way)

In file [progrock/cppx/cloning_util.h]:

#define CPPX_IMPLEMENT_CLONING( Class )                             \
    virtual Class*                                                  \
        virtualCloneThatIsUnsafeToCallDirectly() const              \
    {                                                               \
        assert( typeid( *this ) == typeid( Class ) );               \
        return new Class( *this );                                  \
    }                                                               \
                                                                    \
    ::progrock::cppx::Ownership< Class >                            \
        clone() const                                               \
    {                                                               \
        return ::progrock::cppx::Ownership< Class >(                \
            virtualCloneThatIsUnsafeToCallDirectly()                \
            );                                                      \
    }

And usage, in the same program as before (except the changeover from std::auto_ptr to cppx::Ownership):

Example of mixing in a macro clone implementation:

#include <progrock/cppx/cloning_util.h>
namespace cppx = progrock::cppx;

#include <iostream>
#include <stdexcept>    // std::runtime_error, std::exception
#include <memory>       // std::auto_ptr
#include <assert.h>     // assert
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE

class Exception
    : public std::runtime_error
{
public:
    CPPX_IMPLEMENT_CLONING( Exception )
    typedef std::runtime_error      Base;

    Exception( char const* s ): Base( s ) {}
    virtual bool throwSelf() const { throw *this; }
};

class FooException
    : public Exception
{
public:
    CPPX_IMPLEMENT_CLONING( FooException )
    typedef Exception               Base;

    FooException( char const* s ): Base( s ) {}
    virtual bool throwSelf() const { throw *this; }
};

class BarException
    : public Exception
{
public:
    CPPX_IMPLEMENT_CLONING( BarException )
    typedef Exception               Base;

    BarException( char const* s ): Base( s ) {}
    virtual bool throwSelf() const { throw *this; }
};

//... The rest as before, modulo replacement of std::auto_ptr with Ownership.

Of course, the easiest way for you to use this macro is to replace the cppx::Ownership with e.g. std::auto_ptr.

Anyway, … enjoy! :-)

About these ads

2 comments on “[cppx] 3 ways to mix in a generic cloning implementation

  1. Pingback: 2010 in review | Alf on programming (mostly C++)

  2. Pingback: C++: Polymorphic cloning and the CRTP (Curiously Recurring Template Pattern) | Katy's Code

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s