Lumiera  0.pre.03
»edit your freedom«
virtual-copy-support.hpp File Reference

Go to the source code of this file.

Description

Helper for building »virtual copy« operations.

Especially in conjunction with type erasure, sometimes we have to deal with situations, where we want to copy or assign an object without knowing the full implementation type. Obviously, the default (compiler generated) operations will not work in such situations – even worse, they will slice the objects on copy. The reason is: we must know the full implementation and storage layout of a type do provide any meaningful copy, assignment or move operation.

A possible workaround is to call into the actual implementation type through a virtual function (which requires a VTable): Even if everyone else has ceded ("erased") any knowledge regarding the exact implementation type, the function pointers in the VTable still implicitly hold onto that precise implementation type, since they were set up during construction, where the type was still available. Such a scheme of dealing with "opaque" copy operations is known as virtual copy — it can be dangerous and tricky to get right and preferably it is used only in flat and effectively closed class hierarchies.

This helper template simplifies the construction of such a scheme.

  • a base interface defines the available virtual copy operations
  • a set of CRTP-style templates covers all the cases of
    • full copy support
    • copy construction but no assignment
    • only move construction allowed
    • non-copyable type
  • we use type traits and a policy template to pick the correct implementation for a given data type. Any assignment or copy operations not supported by the target type will be replaced by an implementation which raises a runtime error (Exception); due to relying on virtual functions, unfortunately the check and error can not happen at compile time.
prerequisites
The actual implementation type needs to provide the necessary standard / custom copy and assignment operations with the usual signature. Moreover, the implementation type provides a static function downcast(Base&) to perform a suitable dynamic or static downcast from the interface type to the concrete implementation type.

Usage

The provided virtual operations are to be used in "backward" direction: invoked on the source and affecting the target. The source, through the VTable, knows its precise type and data layout. The target is handed in as parameter and treated by the downcast() function — which preferably performs a dynamic cast (or at least asserts the correct type). This whole scheme can only work for copy and assignment of objects, which actually have the same implementation type – it will never be possible to "cross copy" to an completely unrelated target type, at least not generically.

Usage example

Variant (Variant const& ref)
{
ref.buffer().copyInto (&storage_);
}
Variant&
operator= (Variant const& ovar)
{
ovar.buffer().copyInto (this->buffer());
return *this;
}
Buffer const&
buffer() const
{
return *reinterpret_cast<const Buffer*> (&storage_);
}

In this example, the concrete implementation of the Buffer interface will mix in the Policy template with the implementations of the virtual copy operations. The copy constructor uses the virtual copyInto(void*) to perform a "placement new", whereas the assignment operator calls the virtual copyInto(Buffer&) to downcast the target Buffer and in the end invokes the assignment operator on the concrete Buffer implementation subclass.

Warning
please make sure that only the virtual copy operation is invoked, since this operation will delegate to the copy operation on the implementation class and thus already invoke the whole chain of custom / compiler generated copy implementations. Ignoring this warning can lead to insidious slicing or partial copies. Additionally, if you really need multiple level deep inheritance, you need to mix in the copy implementations on every level again, and you need to provide custom copy operations on every level.
please ensure the target storage for copy/clone is properly aligned. TICKET #1204
See also
VirtualCopySupport_test
lib::Variant usage example

Definition in file virtual-copy-support.hpp.

#include "lib/error.hpp"
#include <type_traits>
#include <utility>

Classes

class  CloneSupport< I, D, B >
 
struct  CopySupport< X, SEL >
 Policy to pick a suitable implementation of "virtual copy operations". More...
 
struct  CopySupport< X, enable_if< supports_cloning< X > > >
 
struct  CopySupport< X, enable_if< supports_copy_and_assignment< X > > >
 
struct  CopySupport< X, enable_if< supports_only_move< X > > >
 
struct  EmptyBase
 
class  FullCopySupport< I, D, B >
 
class  MoveSupport< I, D, B >
 
class  NoCopyMoveSupport< I, D, B >
 
struct  supports_cloning< X >
 
struct  supports_copy_and_assignment< X >
 
struct  supports_only_move< X >
 
class  VirtualCopySupportInterface< IFA, BASE >
 

Namespaces

 lib
 Implementation namespace for support and library code.