ATL Copy Policy Classes
Implementing an STL-Based Collection
Copy policy classes are used to initialize, copy, and delete data. Copy policy classes allow you to define copy semantics for any type of data, and to define conversions between different data types.
ATL uses copy policy classes in its implementations of the following templates:
By encapsulating the information needed to copy or convert data in a copy policy class that can be passed as a template argument, the ATL developers have provided for extreme reusability of these classes. For example, if you need to implement a collection using any arbitrary data type, all you need to provide is the appropriate copy policy; you never have to touch the code that implements the collection.
Definition
Any class that provides the following static functions is a copy policy class:
static void init(DestinationType* p);
static HRESULT copy(DestinationType* pTo, const SourceType* pFrom);
static void destroy(DestinationType* p);
The types DestinationType and SourceType can be replaced with arbitrary data types for each copy policy.
init is used to initialize data, copy to copy data, and destroy to free the data. The precise meaning of initialization, copying, and destruction are the domain of the copy policy class and will vary depending on the data types involved.
There are two guarantees on the use of a copy policy class:
The first parameter to copy will only ever receive a pointer to data that has previously been initialized via init.
destroy will only ever receive a pointer to data that has previously been initialized via init or copied via copy
The only requirement on the implementation of a copy policy class is that it behaves correctly given these guarantees.
Note Although copy policy classes can be defined for any arbitrary data types, their use within ATL code will limit the types that make sense. For example, when using a copy policy class with ATL's collection or enumerator implementations, DestinationType must be a type that can be used as a parameter in a COM interface method.
Standard Implementations
ATL provides two copy policy classes in the form of the _Copy and _CopyInterface template classes:
The _Copy class allows homogeneous copying only (not conversion between data types) since it only offers a single template parameter to specify both DestinationType and SourceType. The generic implementation of this template contains no initialization or destruction code and uses memcpy to copy the data. ATL also provides specializations of _Copy for VARIANT, LPOLESTR, OLEVERB, and CONNECTDATA data types.
The _CopyInterface class provides an implementation for copying interface pointers following standard COM rules. Once again this class allows only homogenous copying, so it uses simple assignment and a call to AddRef to perform the copy.
Custom Implementations
Typically, you'll need to define your own copy policy classes for heterogeneous copying (that is, conversion between data types). For some examples of custom copy policy classes, look at the files VCUE_Copy.h and VCUE_CopyString.h in the project. These files contain two template copy policy classes, GenericCopy
and MapCopy
, plus a number of specializations of GenericCopy
for different data types.
GenericCopy
allows you to specify the SourceType and DestinationType as template arguments. Here's the most general form of the GenericCopy
class from VCUE_Copy.h:
template <class DestinationType, class SourceType = DestinationType>
class GenericCopy
{
public :
typedef DestinationType destination_type;
typedef SourceType source_type;
static void init(destination_type* p)
{
_Copy<destination_type>::init(p);
}
static void destroy(destination_type* p)
{
_Copy<destination_type>::destroy(p);
}
static HRESULT copy(destination_type* pTo, const source_type* pFrom)
{
return _Copy<destination_type>::copy(pTo, const_cast<source_type*>(pFrom));
}
}; // class GenericCopy
VCUE_Copy.h also contains the following specializations of this class: GenericCopy<BSTR>
, GenericCopy<VARIANT, BSTR>
, GenericCopy<BSTR, VARIANT>
. VCUE_CopyString.h contains specializations for copying from std::strings: GenericCopy<std::string>
, GenericCopy<VARIANT, std::string>
, and GenericCopy<BSTR, std::string>
. You could enhance GenericCopy
by providing further specializations of your own.
MapCopy
assumes that the data being copied will be stored in an STL-style map, so it allows you to specify the type of map in which the data is stored and the destination type. The implementation of the class just uses the typedefs supplied by the MapType class to determine the type of the source data and to call the appropriate GenericCopy
class. No specializations of this class are needed.
template <class MapType, class DestinationType = MapType::referent_type>
class MapCopy
{
public :
typedef DestinationType destination_type;
typedef MapType::value_type source_type;
typedef MapType map_type;
typedef MapType::referent_type pseudosource_type;
static void init(destination_type* p)
{
GenericCopy<destination_type, pseudosource_type>::init(p);
}
static void destroy(destination_type* p)
{
GenericCopy<destination_type, pseudosource_type>::destroy(p);
}
static HRESULT copy(destination_type* pTo, const source_type* pFrom)
{
return GenericCopy<destination_type, pseudosource_type>::copy(pTo, &(pFrom->second));
}
}; // class MapCopy