Archive

Archive for June, 2012

Virtual move constructor

June 27, 2012 8 comments

Virtual constructor: recap

Most experienced C++ developers should be familiar with the virtual constructor idiom, which allows us to duplicate a polymorphic object where we do not know its exact type, only the base.

It is usually called clone and can be implemented and used as shown in this rather contrived example:

struct fruit {
	virtual ~fruit() {}

	virtual std::unique_ptr<fruit> clone() const = 0;
};

struct apple
	: fruit
{
	virtual std::unique_ptr<fruit> clone() const {
		return std::unique_ptr<fruit>( new apple(*this) );
	}
};

// orange, pear, roddenberry etc...

int main() {
	const fruit& f = apple();
	auto fc = f.clone();
}

Note that when using unique_ptr we lose the ability to have covariant return types, since unique_ptr< apple > is not derived from unique_ptr< fruit >. In my experience I’ve never needed a derived-type copy out of clone (outside of unit testing anyway), so the covariance offers me nothing, whereas the unique_ptr gives me that nice warm fuzzy feeling :-)

Virtual move constructor

Now, it may seem odd to want a virtual move constructor – why would I want to move an object’s content into a new object rather than continue using the old object? I’ll give the use case below, but for now just take as read that it might be helpful :-)

It’s rather easy to implement if you already know the virtual constructor idiom, as we only need to remove the constness and generate an rvalue reference to *this.

Building on the above example we have:

struct fruit {
	virtual ~fruit() {}

	virtual std::unique_ptr<fruit> clone() const = 0;
	virtual std::unique_ptr<fruit> move_clone() = 0; // clearly non-const
};

struct apple
	: fruit
{
	virtual std::unique_ptr<fruit> clone() const; /* as before */

	virtual std::unique_ptr<fruit> move_clone()  {
		return std::unique_ptr<fruit>( new apple( std::move(*this) ) );
	}
};

If we’re wanting a virtual move constructor then we’re likely to want to create move constructors for the classes as well, but I’ve left that out from here.

But…why?

So I know the concept of a virtual move constructor seems odd, but I’ve got a use case I can think of no better solution for than this:

  • We have a non-copyable polymorphic buffer object that we wish to move ownership of into a functor, which will be run exactly once passing ownership elsewhere. Due to the constraints of the system (and following standard library convention) this functor must be copyable.
  • To safely enable the functor to be copyable we convert the unique_ptr< buffer > into a shared_ptr inside the functor.
  • Once the functor has run we wish to release ownership of the buffer from the shared_ptr…but shared_ptr doesn’t provide a release method.
  • So we ‘move clone’ the shared buffer instance to release its internally-owned resources to a new instance, allowing shared_ptr to destroy the now ‘zombified’ original instance.

I couldn’t find any mentions of ‘virtual move constructor’ about, so it’s likely I’m doing something so ridiculous that nobody else has thought of it. I can’t see any alternatives that wouldn’t require making buffer copyable and maintaining an internal reference count however (which would be comparable performance to this solution, but with more pain and maintenance), so comments and alternative solutions are welcome.

Categories: Uncategorized Tags: ,
Follow

Get every new post delivered to your Inbox.